Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Указатели на объекты С++ IAR EWAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
VladimirYU
Столкнулся с непонятной вещью. Имеется некий класс TBase

в хидере
Код
[/code]
class TBase
{
public: TBase( UCHAR par1, UCHAR par2) // конструктор с двумя параметрами

// Далее методы, данный и т.д.
.........
.........
};
[code]


В file.cpp реализация.

В прилложении создаются объявляются глообальные указатели и создаются два объекта
1 способ, не работает
Код
[/code]
TBase *Obj[2];

// далее вызов конструкторов

Obj[0] = new TBase( A, B);
Obj[1] = new TBase( C, D);

// Методы вызываются в основной программе
Obj[0] ->Method1();
Obj[1] ->Method1();
..........
[code]


Поведение программы, как будто создан только один объет Obj[0]
А если сделать вот так
Код
[/code]
TBase *Obj0;
TBase *Obj1;
// далее вызов конструкторов

Obj0 = new TBase( A, B);
Obj1 = new TBase( C, D);

// Методы вызываются в основной программе

Obj0 ->Method1();
Obj1 ->Method1();
[code]

Все работает корректно.
В чем может быть причина или где я не догоняю
Quasar
VladimirYU привели бы весь код, или подробнее объясните, что значит программа ведет себя как будто создан только один объект? Судя по вашему коду, все должно работать корректно.
SmSp
А если объявить так?

TBase (*Obj)[2];
visual_wind
To SmSp:
В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.

В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел.
VladimirYU
Цитата(visual_wind @ Sep 17 2009, 12:13) *
To SmSp:
В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.

В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел.

К сожалению реализация как конструкторов, так и методов скрыта и доступна только в виде библиотек .r90
jorikdima
Зачем в АВР динамически выделяемые объекты? И вообще, кто у вас там память выделяет/распределяет? Размер кучи достаточен?
visual_wind
To VladimirYU:

Так а стало понятно, что не работает в варианте с массивом, или, поскольку все заработало в варианте без массива, то все ок и дальше нет смысла копаться?

Если есть необходимость разбираться дальше:

Из-под ссей можно еще просмотреть корректность работы оператора new (в разных ли местах выделяется память под рассматриваемые два экземпляра и с правильными ли параметрами вызываются конструкторы TBase). Возможно, кстати, что класс TBase перегружает operator new и там какой-то глюканат из-за оптимизации, например. Если есть полное описание класса TBase, можно еще после конструирования попытаться проверить корректность инициализации переменных класса TBase конструктором.

Если полного описания класса нет, а только интерфейс, шанс еще есть в анализе дизассемблерного кода.
SmSp
Цитата(visual_wind @ Sep 17 2009, 12:13) *
To SmSp:
В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.

В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел.

Путаешь.
TBase (*Obj)[2]; // обявлен массив из двух указателей на Obj
TBase *(Obj[2]); // обявлен указатель на массив из двух Obj
Не помню, у чего тут больше приоритет, поэтому предположил автору убедиться что объявлил он то что хотел.
visual_wind
To SmSp:

Могу и ошибаться. Чтоб лишний раз не спорить, предлагаю посмотреть Кернигана/Ричи, стр.111, последний абзац.

Что касается приоритетов, то поскольку приоритет оператора[] выше приоритета оператора*, то использовать скобки в варианте TBase *(Obj[2]) смысла нет, а в варианте TBase (*Obj)[2] скобки как раз меняют приоритеты, то есть, сначала operator*, затем operator[], затем TBase. Итого, Obj есть указатель (operator*) на массив (operator[]) из двух ([2]) TBase.
SmSp
Дык, ёлки!

Всё верно, точнее у VladimirYU ошибка. Он обявил указатель на массив из двух TBase:

TBase *Obj[2];

Не забываем что массив в си есть указатель на первый элемент массива, имеет тип *TBase. Так, Obj есть указатель на указатель на первый элемент массива из TBase.

Первой строкой разименовал указатель (Obj[0] == *(Obj+0)), записал туда указатель на свежесозданный экземпляр TBase. Имеем указатель на указатель на массив, первый элемент которого проинициализирован:

Obj[0] = new TBase( A, cool.gif;

Вторая строка записывает указатель на свжесозданный экземпляр TBase по адресу Obj + 1:

Obj[1] = new TBase( C, D);

А это ошибка, т.к. используем указатель как массив, в итоге обращаясь к незанятой ячейки памяти.

Всё равно что объявить

TBase* pointer1;

и затем обратиться

*(pointer1 + 1) = bla bla;

Отсюда и неправильное поведение программы. Надо внимательнее, это же си.
visual_wind
To SmSp: Мое видение проблемы:

У VladimirYU в том коде, что он привел, ошибок нет. Он НЕ объявлял указатель на массив из двух TBase, для чего надо использовать объявление TBase (*Obj)[2]. Он объявил массив из двух указателей на TBase, для чего и использовал правильное объявление TBase *Obj[2]. Это разные вещи, согласитесь.

Чтобы не пускаться дальше в дискуссию об указателях на указатели и о том, что обозначает имя массива, я в Visual C++ Express Edition 2008 собрал простенький пример.

Код
class TBase
{
private:
    char char1;
    char char2;
public:
    TBase( char c1, char c2 ): char1( c1 ), char2( c2 ) {}
    void Method1(){ cout << char1 << char2; }
    virtual ~TBase(){}
};

TBase* tb[2] = { NULL, NULL };

int _tmain(int argc, _TCHAR* argv[])
{
    tb[0] = new TBase( '1', '2' );
    tb[1] = new TBase( '3', '4' );

    tb[0]->Method1();
    tb[1]->Method1();

    delete tb[0];
    delete tb[1];

    return 0;
}


У меня этот код работает правильно и печатает "1234". Можете проверить у себя.

На мой взляд, проблема у VladimirYU в другом, но пока не понятно в чем.
SmSp
visual_wind, ты же сам написал, что приоритет оператора[] выше приоритета оператора*. Значит, VladimirYU объявил указатель на массив.
А тот факт, что приведённый тобой код работает, означает что программа не затирает указатель по адресу tb+1, что в общем случае он может сделать и делает в программе VladimirYU (цитирую: "как будто создан только один объет Obj[0]").
visual_wind
То SmSp:

По-моему, мы вместо помощи человеку начали разводить флейм и нарываемся на бан. И камень преткновения - что же на самом деле объявлено - указатель на массив из двух TBase или массив из двух указателей на TBase. Обратимся непосредственно к K&R:

"Таким образом, если массив daytab передается некоторой функции f, то эту функцию можно было бы определить следующим образом
f( char daytab[2][13] ){...}
Вместо этого можно записать
f( char daytab[][13] ){...}
поскольку число строк здесь не имеет значения, или
f( char (*daytab)[13] ){...}
последняя запись декларирует, что параметр есть указатель на массив из 13 значений типа char. Скобки здесь необходимы, так как квадратные скобки [] имеют более высокий приоритет, чем *. Без скобок декларация
f( char *daytab[13] ){...}
определяет массив из 13 указателей на char. В более общем случае только первое измерение (соответствующее первому индексу) можно не задавать, все другие специфицировать необходимо" © K&R, стр.111-112, изд.2-е, переработанное,1992.

Насколько я понимаю, у VladimirYU все в порядке в том коде, который он привел.
Quasar
Цитата(SmSp @ Sep 18 2009, 15:43) *
Он обявил указатель на массив из двух TBase:

Ни чего он такого не объявлял.

Цитата('SmSp' date='Sep 18 2009 @ 15:43' post='651718')
Надо внимательнее, это же си.

Вот именно.

Возмите, да под какой-нибудь системой(которая способна ошибку сегментации выдать) соберите код:
Код
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void){
    int i,*arr[10],*arr2[10];
    printf("Part 1\n");
    for (i = 0; i < (sizeof(arr)/sizeof(int*));i++){
        printf ("i = %d\n",i);
        arr[i] = (int*)malloc(sizeof(int));
        *arr[i] = i;
    }
    for (i = 0; i < (sizeof(arr)/sizeof(int*));i++){
        printf ("n = %d\n",*arr[i]);
    }
    printf ("Part 2\n");
    for (i = 0; i < (sizeof(arr2)/sizeof(int*));i++){
        printf ("i = %d\n",i);
        *arr2[i] = i;
    }
    return 0;
}


VladimirYU
Проблема где-то не в массиве.
VladimirYU
Цитата(Quasar @ Sep 21 2009, 02:07) *
VladimirYU
Проблема где-то не в массиве.

Я тоже к этому склоняюсь, но дело в том, что объекты в моем случае это физические приборы обращение к которым от "мамы" по SPI шине. Реализация класса, поддерживающего их, скрыта, есть только интерфейс .h и .r90. В общем пока обхожу эту проблему, но в дальнейшем придется разбираться. Всем спасибо за участие, за одно и лишний раз в стандарте покапался.
SmSp
Вы правы. Сверился с Керниган/Ричи - объявлен массив указателей.

Тогда в самом деле непонятно. Дело не в конструкторе, т.к. всё работает с отдельными указателями. Думаю, тут дело в кривизне компилятора по части работы с массивами указателей.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.