proper way to de-alloc list<type*> ?

Started by
10 comments, last by Tyson 20 years, 10 months ago
I was just wondering what the accepted "correct" way was to clear an STL list of pointer types. What way will do it correctly without invalidating any iterator you may be using during the clearing process? eg:
  
list<string*> myList;

myList.push_back( new string("test") );

list<string*>::iterator it;
for(it=myList.begin(); it != myList.end();it++)
{
  delete *it;
}

myList.clear();

  
is that a correct way to do it? Thanks! ============================ A guy, some jolt, and a whole lot of code
============================A guy, some jolt, and a whole lot of code :)
Advertisement
Yes, that's the way. It doesn't invalidate iterators, in fact it doesn't even alter the data stored in the container (the pointers). It simply deletes the data where the elements point at.

Someone is bound to nag you about this though:

"it++"

So I'll just have to nag first . When using other than primitive types,

"++it"

is faster. myList.end() requires a copy so it isn't superfast either. Here's a fast version:


    list<string*>::iterator it = myList.begin();list<string*>::iterator eit = myList.end();for(; it != eit; ++it){  delete *it;}    


[edited by - civguy on May 28, 2003 5:26:43 PM]
That''s how I clear a container of pointers; loop through all elements and free the allocated memory, and then clear the entire container. delete *it will not affect the iterator, so it shouldn''t invalidate any iterators.

But I have some things to say about your for loop. end() will, unless the compiler is able to see that the container isn''t changed, be evaluated every iteraton. i++ should be ++i. May not matter much now when the datatype is a simple pointer, but for complex objects you should definitely use pre-in/decrements as they don''t have to mess with copies of objects. So get used to pre-in/decrements.
It's worth mentioning why the prefix operator is "faster". The general convention is for the prefix operator to simply increment the value and return a reference to it, where as postfix operators store a copy of the value, increment the original, and return the copy. If the "create a copy" operation is costly, or is done a large number of times, it will run slower.

- Jason Citron
- ZeroInfinity Studios
- www.zeroinfinity.net

[edited by - clash on May 28, 2003 5:34:17 PM]
- Jason Citron- Programmer, Stormfront Studios- www.stormfront.com
Thanks for the great replies! I was aware that ++i is faster than i++ but I never even thought about that. The end() call is a good thing too. Thanks everyone
============================A guy, some jolt, and a whole lot of code :)
If you are storing pointers in a STL container you could put them in an smart pointer (don''t use auto_ptr though), then you don''t have to care about deleting them, the destructor will take care of it for you.

Instead of:

  std::list<string*> myList;myList.push_back(new string("test"));...for (std::list<string*>::iterator it = myList.begin(); it != myList.end(); ++it){   delete *it;}myList.clear();  

You would have:

  typedef boost::shared_ptr<string> SharedStringPtr;std::list<SharedStringPtr> myList;myList.push_back(SharedStringPtr(new string("test")));...myList.clear();  


[How To Ask Questions|STL Programmer''s Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]
Arguing on the internet is like running in the Special Olympics: Even if you win, you're still retarded.[How To Ask Questions|STL Programmer's Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]
dalleboy, if the container is made to own the pointers, why be so wasteful? I changed some of my older code to use smart pointers (boost''s shared_ptr) and it became some 20% slower and I even had to write more code than the raw pointer solution used. For resources that have a clear owner (such as a single STL container), I don''t suggest using smart pointers.
quote:Original post by civguy
dalleboy, if the container is made to own the pointers, why be so wasteful?

Because it is simpler plus you won''t get any memory leaks. The boost::shared_ptr was just a suggestion, you could write your own smart pointer if you want to and are into optimization.

[How To Ask Questions|STL Programmer''s Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]
Arguing on the internet is like running in the Special Olympics: Even if you win, you're still retarded.[How To Ask Questions|STL Programmer's Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]
The reason to use smart-pointers in STL containers is for exception safety.
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
quote:Original post by civguy
dalleboy, if the container is made to own the pointers, why be so wasteful?

quote:Original post by dalleboy
Because it is simpler plus you won't get any memory leaks. The boost::shared_ptr was just a suggestion, you could write your own smart pointer if you want to and are into optimization.
Simpler? You have to either .get() the raw pointer out of the smart one to pass it around or then make all your functions use smart pointers. Hardly compensates for the small gain in deleting the data from the container, which can be templated to work like this:
deleteContainer(cont);  

Making your own smart pointer that is faster than boost::shared_ptr is yet less simple.

I don't know how it solves memory leaks either. If it was totally transparent, it would solve them. But now that I have to actively type
typedef boost::shared_ptr SharedStringPtr;
And then use SharedStringPtr everywhere, so it's actually more burden than adding a deleteContainer(cont); into the destructor.

edit: sigh, I had just recently been doing stuff where I only had to add stuff to container, not delete anything from it except clear it every once in a while, so I oversimplified this. But naturally one has to call delete each time an item is popped from the container, not just when the whole container is erased, and that adds some remembering burden that shared pointers would take care of.
quote:The reason to use smart-pointers in STL containers is for exception safety.
If the container's elements are deleted in a destructor and along the way as items are removed from the container, it's no less exception safe than a container using smart pointers. Try/catch helps where RAII is too much of a burden.

[edited by - civguy on May 29, 2003 3:01:29 PM]

This topic is closed to new replies.

Advertisement