views:

103

answers:

5

Hi all,

Problem:

I try to deallocate memory pointed by pointer items of an STL list.

This should work fine but in my case, there can be duplicate pointers in the list and I get a double dealloc exception even though I test whether the pointer is NULL or not (see source code below). How can I solve this problem ?

Environment:

  • Debian5 Lenny
  • gcc version 4.3.2 (Debian 4.3.2-1.1)
  • libc-2.7.so
  • libstdc++.so.6.0.10
  • Eclipse Galileo Build id: 20100218-1602 / CDT.

C++ source code:

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();

Error displayed:

*** 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
+1  A: 

You can create temporary std::set, fill it with items of your original container, and delete all items of set in cycle (set guarantees that we will have only unique items).
Or you can apply std::unique function to your container.
But I suggest you to use smart pointers (something like boost::shared_ptr). They will do all work about memory management.

vnm
+1 for the `set` suggestion
jpalecek
A: 

You're only creating one line object (there is only one new)

But you're deleting it twice because you put the same object into the list twice.

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);
Andre Holzner
+4  A: 
l->push_back(line);
l->push_back(line);

This will just insert 2 pointers to the same reference.

delete (*it);

Thus when you call this for the 1st line, the original Line will be lost. The 2nd Line will now point to a deallocated object.


Why not just use list<Line> (without the pointer)? This avoids the new/delete issue altogether, at the expense of storing by-value.

Or use shared_ptr as in @Edric's answer.

KennyTM
A: 

Line is allocated once, but added twice to your list. The first delete will free the allocated memory. The second delete will complain about it. This is perfectly normal.

Consider using e.g. reference-counted smart pointers instead of normal pointers.

Patrick
Thanks for your help but it would be normal if by setting the pointer to NULL, we would not go into the condition afterwards.Instead, even if I set the pointer to NULL, the next iteration, it still sees it as not null, no ?
TMA
By setting the pointer to NULL, you are actually setting the element of the list to NULL. The next entry in the list will still contain a non-NULL pointer.
Patrick
+5  A: 

Can you use smart pointers rather than raw pointers? I would try using boost shared_ptrs, like so:

#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 );

When the list is destroyed, the boost::shared_ptr cleanup will delete the Line objects.

Edric
Thanks a lot, this solves my problem!As I was using libboost already, this is just fine :)
TMA