C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Продолжаем о динамическом TImage, Теперь их много, и они в векторе
exp
Отправлено: 09.11.2005, 23:34


Мастер участка

Группа: Участник
Сообщений: 304



Никогда бы не подумал, что напорюсь на такую ошибку...
Вот кусочек кода, который заполняет вектор Images картинками.
Номер картинки я храню, поэтому использую структуру

CODE

struct TImageEx
       {
           int Number;
           TImage *Img;
       };

Вот код.
CODE

   int PicWidth = DeltaX+20;      
   int PicHeigth = DeltaY+20;    

   int Pole = 20;                  
   int Otstup = 10;              

   int X = Pole;
   int Y = Pole;

   sbScroll->VertScrollBar->Position = 0;
   sbScroll->HorzScrollBar->Position = 0;

   
for(unsigned int i = 0; i < Zerna.size(); i++)
   {
       if((X+PicWidth)>=sbScroll->Width)
       {
           X = Pole;
           Y += PicHeigth+Otstup;
       }

       TImageEx NewImage;
       NewImage.Img = new TImage(imPrototype);
       NewImage.Img->Left = X;
       NewImage.Img->Top = Y;
       NewImage.Img->Parent = sbScroll;
       NewImage.Img->Width = PicWidth;
       NewImage.Img->Height = PicHeigth;
       NewImage.Img->OnClick = ImageClick; // Моя процедура (неважно)
       NewImage.Number = i;
       Images.push_back(NewImage);

       X += PicWidth+Otstup;
   }

Все великолепно создается.
Теперь я вспоминаю, что если загружаю второй файл, то неплохо было бы очиститься от старых значений, и пишу сверху этого кода:
CODE

if(Images.size() > 0)
   {
       for(int i = 0; i < Images.size(); i++)
       delete Images[i].Img;
   }

Результат: При i==(Images.size()-1), т. е. на последнем элементе выскакивает жуткий Exception и говорит мне: "Дорогой, у меня Access violation по адресу 00000000. Read of adress 00000000. Используй Step or Run to continue."
То же получается, если вызывать деструктор Images[i].Img->~TImage().

Я попробовал начать процесс с конца вектора. Эффект слегка приятный, но и несколько необъяснимый: жуткий Exception выскакивает на 16 (не крайнем!) элементе вектора. С одной стороны приятно, что последний элемент при этом благополучно удаляется, но с другой стороны непонятно, почему ошибка выскакивает посреди вектора, да и почему она вобще выскакивает.

У кого какие соображения по этому поводу?
Asher
Отправлено: 10.11.2005, 09:51


Мастер участка

Группа: Модератор
Сообщений: 550



Привет.
все Ваши TImageEx NewImage; создаются на стеке и при выходе из подпрограммы создания уничтожаются.
Чтобы это нормально работало надо создавать их в динамической памяти, через TImageEx *pNewImage = new TImageEx();
То, что ошибка происходит не везде говорит только о том, что эту память никто испортить не успел
exp
Отправлено: 10.11.2005, 10:06


Мастер участка

Группа: Участник
Сообщений: 304



vector::push_back(Object &) создает динамически объект для себя по образу и подобию указанного в параметре. Тысячу раз делал так, как написано, и все было Ок.

Попробовал выделать память динамически — тот же результат.
Кто сталкивался с векторами VCL-объектов откликнитесь, может есть какие-то тонкости?....
exp
Отправлено: 10.11.2005, 10:57


Мастер участка

Группа: Участник
Сообщений: 304



Хочется воскликнуть вслед за персонажами из рекламы: "Да, сынок, это — фантастика!".
Меняю код очистки памяти на следующий:
CODE

if(Images.size() > 0)
{
while(Images.size()>0)
{
delete Images[0].Img;
Images.erase(&Images[0]);
}
}

И... все работает.
Давайте разберемся, почему Это (см. выше) работает, а это (см. ниже) нет.
CODE

if(Images.size() > 0)
{
for(int i = 0; i<(Images.size(); i++) delete Images[0].Img;
Images.erase(Images.begin(), Images.end());
}


Отредактировано exp — 10/11/2005, 10:57
Asher
Отправлено: 10.11.2005, 11:01


Мастер участка

Группа: Модератор
Сообщений: 550



В первом своем посте был не прав. У Вас там вектор элементов (не указателей) и при вставке действительно отработает конструктор копии.

QUOTE
Давайте разберемся, почему Это (см. выше) работает, а это ()см. ниже) нет.

А там точно delete Images[0].Img; ? не описка?

Отредактировано Asher — 10/11/2005, 12:05
exp
Отправлено: 10.11.2005, 11:04


Мастер участка

Группа: Участник
Сообщений: 304



но могу же я сделать
CODE

vector<double> vDouble();

vDouble.push_back(7); // то есть запихнуть в вектор константу без
                                     //  всякого адреса

И эта константочка будет великолепно там храниться.
exp
Отправлено: 10.11.2005, 11:06


Мастер участка

Группа: Участник
Сообщений: 304



QUOTE
А там точно delete Images[0].Img; ? не описка?


Точно.

И еще забава: Сделал отдельный прект, который заполняет вектор картинками, и с очисткой памяти с for — работает.
Может это у меня в проекте волшебство затаилось?
Asher
Отправлено: 10.11.2005, 11:07


Мастер участка

Группа: Модератор
Сообщений: 550



Да, я понял уже. см. пост выше.

P.S. что там за пустой пост со словом vector? удалить?
Asher
Отправлено: 10.11.2005, 11:09


Мастер участка

Группа: Модератор
Сообщений: 550



Я имею ввиду в этом коде
CODE
if(Images.size() > 0)
  {
      for(int i = 0; i<(Images.size(); i++) delete Images[0].Img;
      Images.erase(Images.begin(), Images.end());
  }

Почему написано delete Images[0].Img;
Должно же быть delete Images[i].Img;
exp
Отправлено: 10.11.2005, 11:11


Мастер участка

Группа: Участник
Сообщений: 304



Не.. smile.gif это я просто ручками код на форуме правил. Там действительно вместо 0 должно быть i.
exp
Отправлено: 10.11.2005, 11:13


Мастер участка

Группа: Участник
Сообщений: 304



QUOTE

P.S. что там за пустой пост со словом vector? удалить?

А это где? Не вижу.

Вернуться в Вопросы программирования в C++Builder