|
Указатели на объекты С++ IAR EWAVR |
|
|
|
Sep 1 2009, 13:09
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Столкнулся с непонятной вещью. Имеется некий класс 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] Все работает корректно. В чем может быть причина или где я не догоняю
|
|
|
|
|
Sep 17 2009, 06:58
|
Группа: Участник
Сообщений: 11
Регистрация: 26-02-08
Пользователь №: 35 394

|
А если объявить так?
TBase (*Obj)[2];
|
|
|
|
|
Sep 17 2009, 08:13
|
Группа: Участник
Сообщений: 8
Регистрация: 29-04-09
Из: Харьков
Пользователь №: 48 442

|
To SmSp: В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.
В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел.
Сообщение отредактировал visual_wind - Sep 17 2009, 08:14
|
|
|
|
|
Sep 17 2009, 09:51
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(visual_wind @ Sep 17 2009, 12:13)  To SmSp: В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.
В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел. К сожалению реализация как конструкторов, так и методов скрыта и доступна только в виде библиотек .r90
|
|
|
|
|
Sep 18 2009, 06:33
|
Группа: Участник
Сообщений: 8
Регистрация: 29-04-09
Из: Харьков
Пользователь №: 48 442

|
To VladimirYU:
Так а стало понятно, что не работает в варианте с массивом, или, поскольку все заработало в варианте без массива, то все ок и дальше нет смысла копаться?
Если есть необходимость разбираться дальше:
Из-под ссей можно еще просмотреть корректность работы оператора new (в разных ли местах выделяется память под рассматриваемые два экземпляра и с правильными ли параметрами вызываются конструкторы TBase). Возможно, кстати, что класс TBase перегружает operator new и там какой-то глюканат из-за оптимизации, например. Если есть полное описание класса TBase, можно еще после конструирования попытаться проверить корректность инициализации переменных класса TBase конструктором.
Если полного описания класса нет, а только интерфейс, шанс еще есть в анализе дизассемблерного кода.
|
|
|
|
|
Sep 18 2009, 06:48
|
Группа: Участник
Сообщений: 11
Регистрация: 26-02-08
Пользователь №: 35 394

|
Цитата(visual_wind @ Sep 17 2009, 12:13)  To SmSp: В этом случае получится не массив из двух указателей на TBase, а указатель на массив из двух TBase.
В коде, который привел VladimirYU, вроде все правильно, возможно, траблы были именно в реализации конструктора TBase или функции-члена Method1(), которые автор не привел. Путаешь. TBase (*Obj)[2]; // обявлен массив из двух указателей на Obj TBase *(Obj[2]); // обявлен указатель на массив из двух Obj Не помню, у чего тут больше приоритет, поэтому предположил автору убедиться что объявлил он то что хотел.
|
|
|
|
|
Sep 18 2009, 08:57
|
Группа: Участник
Сообщений: 8
Регистрация: 29-04-09
Из: Харьков
Пользователь №: 48 442

|
To SmSp:
Могу и ошибаться. Чтоб лишний раз не спорить, предлагаю посмотреть Кернигана/Ричи, стр.111, последний абзац.
Что касается приоритетов, то поскольку приоритет оператора[] выше приоритета оператора*, то использовать скобки в варианте TBase *(Obj[2]) смысла нет, а в варианте TBase (*Obj)[2] скобки как раз меняют приоритеты, то есть, сначала operator*, затем operator[], затем TBase. Итого, Obj есть указатель (operator*) на массив (operator[]) из двух ([2]) TBase.
Сообщение отредактировал visual_wind - Sep 18 2009, 08:58
|
|
|
|
|
Sep 18 2009, 11:43
|
Группа: Участник
Сообщений: 11
Регистрация: 26-02-08
Пользователь №: 35 394

|
Дык, ёлки! Всё верно, точнее у VladimirYU ошибка. Он обявил указатель на массив из двух TBase: TBase *Obj[2]; Не забываем что массив в си есть указатель на первый элемент массива, имеет тип *TBase. Так, Obj есть указатель на указатель на первый элемент массива из TBase. Первой строкой разименовал указатель (Obj[0] == *(Obj+0)), записал туда указатель на свежесозданный экземпляр TBase. Имеем указатель на указатель на массив, первый элемент которого проинициализирован: Obj[0] = new TBase( A,  ; Вторая строка записывает указатель на свжесозданный экземпляр TBase по адресу Obj + 1: Obj[1] = new TBase( C, D); А это ошибка, т.к. используем указатель как массив, в итоге обращаясь к незанятой ячейки памяти. Всё равно что объявить TBase* pointer1; и затем обратиться *(pointer1 + 1) = bla bla; Отсюда и неправильное поведение программы. Надо внимательнее, это же си.
Сообщение отредактировал SmSp - Sep 18 2009, 11:46
|
|
|
|
|
Sep 18 2009, 13:22
|
Группа: Участник
Сообщений: 8
Регистрация: 29-04-09
Из: Харьков
Пользователь №: 48 442

|
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 в другом, но пока не понятно в чем.
Сообщение отредактировал visual_wind - Sep 18 2009, 13:42
|
|
|
|
|
Sep 18 2009, 13:41
|
Группа: Участник
Сообщений: 11
Регистрация: 26-02-08
Пользователь №: 35 394

|
visual_wind, ты же сам написал, что приоритет оператора[] выше приоритета оператора*. Значит, VladimirYU объявил указатель на массив. А тот факт, что приведённый тобой код работает, означает что программа не затирает указатель по адресу tb+1, что в общем случае он может сделать и делает в программе VladimirYU (цитирую: "как будто создан только один объет Obj[0]").
|
|
|
|
|
Sep 18 2009, 14:01
|
Группа: Участник
Сообщений: 8
Регистрация: 29-04-09
Из: Харьков
Пользователь №: 48 442

|
То 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 все в порядке в том коде, который он привел.
Сообщение отредактировал visual_wind - Sep 18 2009, 14:03
|
|
|
|
|
Sep 20 2009, 22:07
|

Местный
  
Группа: Свой
Сообщений: 257
Регистрация: 2-12-06
Из: Default City
Пользователь №: 23 021

|
Цитата(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Проблема где-то не в массиве.
|
|
|
|
|
Sep 21 2009, 06:02
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(Quasar @ Sep 21 2009, 02:07)  VladimirYU Проблема где-то не в массиве. Я тоже к этому склоняюсь, но дело в том, что объекты в моем случае это физические приборы обращение к которым от "мамы" по SPI шине. Реализация класса, поддерживающего их, скрыта, есть только интерфейс .h и .r90. В общем пока обхожу эту проблему, но в дальнейшем придется разбираться. Всем спасибо за участие, за одно и лишний раз в стандарте покапался.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|