Before clearing or destructing a STL container containing dynamically allocated pointers, it is important to delete the pointers or else, you are going to leak memory and resources (See item 7 in Effective STL). The usual way to this is:
for( vector<MyClass*>::iterator it = v.begin(), e = v.end(); it != e; ++it ) { delete *it; } v.clear();
There is a small twist with sets. This code would be fine with a set using its default compare function but since sorting pointers with their values is not very useful, most of the time, such containers are configured with a custom compare function that dereference the pointers to perform its comparison. The standard does not specify which set methods use the compare function and which are not. So it is looking for trouble to free the memory and keep the pointers on it in the set and at best your set will be in an invalid state.
The easy way is to store boost::smart_ptr<MyClass*>
into the set. All you have to do is to clear the set and the smart pointers will take care of deallocating the memory. My opinion, however, is that this solution is like using a machine gun to kill a mosquito. The real purpose of smart pointers is for dealing with situations where the pointers ownership is fuzzy. If you know that it is safe without any doubt to delete the pointers in your container when you want to clear it, you should not be using smart pointers.
Another option is to use boost::ptr_set
but since I am not very familiar with this class, this is not something I will recommend.
The best solution that I have seen is simply doing this:
typedef std::set<MyClass*, CompFuncThatDerefencePointers> MySet; for( MySet::iterator it = s.begin(), e = s.end(); it != e; ) { MyClass *p = *it; s.erase(it++); delete p; }
There are 2 more details that I want to discuss. Some STL containers (such as set
and map
) erase()
method signature is
void erase(iterator it);
and some other containers (list
and vector
) have
iterator erase(iterator it);
The second signature makes sense for containers that upon insertion or removal of elements invalidates all iterators on it but I have no idea why list has its erase returning an iterator. If you think that you might switch from a list to an associative container, you might want to erase elements from the list with
l.erase(iter++);
to keep your code compatible with the associative containers interface. As I am writing, I think that the STL designers decided to make the list erase signature compatible with the vector erase
because they considered that this was the most likely switch if you had to change your container strategy.
The other important point that I wanted to mention is that my recommendation to explicitly clear the pointers rather than using boost::smart_ptr
assumes that your container is a data member of a class and that you are using the RAII idiom. That is that you are deleting the container elements memory in the class destructor. This is to be sure that your code is exception-safe. If your container is an automatic variable in a function, then this might be an appropriate situation to use boost::smart_ptr
because if you do not and an exception is thrown before your container clearing code is executed, you will leak memory.
No Comments/Pingbacks for this post yet...
This post has 5 feedbacks awaiting moderation...
Comments are closed for this post.
I want you to find in this blog informations about C++ programming that I had a hard time to find in the first place on the web.
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
---|---|---|---|---|---|---|
<< < | > >> | |||||
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |