двойная проблема с деллоками при очистке списка указателей в C ++ STL - PullRequest
0 голосов
/ 16 августа 2010

Проблема:

Я пытаюсь освободить память, указанную элементами указателя в списке STL.

Это должно работать нормально, но в моем случае в списке могут быть повторяющиеся указатели, и яполучить двойное исключение dealloc, даже если я проверяю, имеет ли указатель значение NULL или нет (см. исходный код ниже).Как я могу решить эту проблему?

Среда:

  • Debian5 Lenny
  • gcc версия 4.3.2 (Debian 4.3.2-1.1)
  • libc-2.7.so
  • libstdc ++. so.6.0.10
  • Eclipse Galileo ID сборки: 20100218-1602 / CDT.

Исходный код C ++:

list<Line *> * l = new list<Line *>;
Line * line = new Line(10, 10, 10, 10);
l->push_back(line);
l->push_back(line);

cout << "line addr " << line << endl;

for (list<Line *>::iterator it = l->begin(); it != l->end(); it++)
 {
  if (*it != NULL)
   {
    cout << "line it " << *it << " " << (*it)->toString() << endl;
    delete (*it);
    (*it) = NULL;
   }
 }
l->clear();

Отображаемая ошибка:

*** glibc detected *** /home/debian/workspace/Scrap/Release/Scrap: double free or corruption (!prev): 0x0846de20 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6[0xb6d68764]
/lib/i686/cmov/libc.so.6(cfree+0x96)[0xb6d6a966]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb6f402e1]
/home/debian/workspace/Scrap/Release/Scrap[0x8067cb0]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb6d10455]
/home/debian/workspace/Scrap/Release/Scrap(_ZNSt8ios_base4InitD1Ev+0x49)[0x8052cd1]
======= Memory map: ========
08048000-0842c000 r-xp 00000000 08:01 3819374 /home/debian/workspace/Scrap/Release/Scrap
0842c000-08451000 rw-p 003e3000 08:01 3819374 /home/debian/workspace/Scrap/Release/Scrap

Ответы [ 5 ]

5 голосов
/ 16 августа 2010

Можете ли вы использовать умные указатели, а не сырые указатели? Я бы попробовал использовать boost shared_ptrs, вот так:

#include <boost/shared_ptr.hpp>

list< boost::shared_ptr< Line > > l;
boost::shared_ptr< Line > line( new Line( 10, 10, 10, 10 ) );
l.push_back( line );
l.push_back( line );

Когда список уничтожен, очистка boost::shared_ptr удалит объекты Line.

4 голосов
/ 16 августа 2010
l->push_back(line);
l->push_back(line);

Это просто вставит 2 указателя на одну и ту же ссылку.

delete (*it);

Таким образом, когда вы вызовете это для 1-й строки, исходная строка будет потеряна.Вторая строка теперь будет указывать на освобожденный объект.


Почему бы просто не использовать list<Line> (без указателя)?Это позволяет полностью избежать проблемы new / delete за счет сохранения побочной стоимости.

Или используйте shared_ptr, как в @ ответ Эдрика .

1 голос
/ 16 августа 2010

Вы можете создать временный std :: set, заполнить его элементами исходного контейнера и удалить все элементы набора в цикле (set гарантирует, что у нас будут только уникальные элементы).
Или вы можете применить функцию std :: unique к вашему контейнеру.
Но я предлагаю вам использовать умные указатели (что-то вроде boost :: shared_ptr). Они сделают всю работу по управлению памятью.

0 голосов
/ 16 августа 2010

Линия выделяется один раз, но добавляется дважды в ваш список. Первое удаление освободит выделенную память. Второе удаление будет жаловаться на это. Это совершенно нормально.

Рассмотрите возможность использования, например, умные указатели с подсчетом ссылок вместо обычных указателей.

0 голосов
/ 16 августа 2010

Вы создаете только один линейный объект (есть только один новый)

Но вы удаляете его дважды, потому что вы помещаете один и тот же объект в список дважды.

Do:

Line * line = new Line(10, 10, 10, 10);
l->push_back(line);
line = new Line(10, 10, 10, 10);   // second new
l->push_back(line);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...