How to use for_each to delete each value on the STL map?

Suppose I have an STL map where the values ​​are pointers and I want to delete all of them. How can I present the following code, but using std :: for_each? I am happy for the decision to use Boost.

for( stdext::hash_map<int, Foo *>::iterator ir = myMap.begin(); ir != myMap.end(); ++ir ) { delete ir->second; // delete all the (Foo *) values. } 

(I found Boost checked_delete , but I'm not sure how to apply this to pair<int, Foo *> , which is an iterator).

(Also, for the purpose of this question, ignore the fact that storing raw pointers that need to be removed in the STL container is not very reasonable).

Note. Subsequently, I found and listed a single-line answer below ... but the code is pretty terrible, so I accepted GMan saner's answer.

+7
c ++ boost algorithm stl
source share
4 answers

You need to create a function object:

 struct second_deleter { template <typename T> void operator()(const T& pX) const { delete pX.second; } }; std::for_each(myMap.begin(), myMap.end(), second_deleter()); 

If you use boost, you can also use the lambda library:

 namespace bl = boost::lambda; std::for_each(myMap.begin(), myMap.end(), second_deleter(), bl::bind(bl::delete_ptr(), bl::bind(std::select2nd<myMap::value_type>(), _1)); 

But you can try the pointer container library that does this automatically.

Please note that you are not using a map, but hash_map . I recommend you switch to boost unordered_map , which is more relevant. However, ptr_unordered_map does not seem to exist.

For security reasons you should wrap this. For example:

 template <typename T, typename Deleter> struct wrapped_container { typedef T container_type; typedef Deleter deleter_type; wrapped_container(const T& pContainer) : container(pContainer) {} ~wrapped_container(void) { std::for_each(container.begin(), container.end(), deleter_type()); } T container; }; 

And use it like:

 typedef wrapped_container< boost::unordered_map<int, Foo*>, second_deleter> my_container; my_container.container./* ... */ 

This ensures that no matter what, your container will be repeated using a deleter. (For exceptions, for example.)

For comparison:

 std::vector<int*> v; v.push_back(new int); throw "leaks!"; // nothing in vector is deleted wrapped_container<std::vector<int*> > v; v.container.push_back(new int); throw "no leaks!"; // wrapped_container destructs, deletes elements 
+14
source share

Have you tried using BOOST_FOREACH? This should allow you to do this in a line without creating your own functor.

I have not tested the following code, but it should look something like this (if not exact):

 typedef stdext::hash_map<int, Foo *> MyMapType; //see comment. BOOST_FOREACH( MyMapType::value_type& p, myMap ) { delete p.second; } 

Well, this is more than 1 line, due to typedef :)

+3
source share

If possible, why not use smart pointers on your map?

0
source share

OK, I found out how to do this in one line ... but I don’t think I would ever do it in real code!

 std::for_each( mayMap.begin() , myMap.end() , boost::bind( &boost::checked_delete<Foo> , boost::bind( &stdext::hash_map<int, Foo *>::value_type::second, _1 ) ) ); 

However, I am going to accept GMan's answer because I like his idea of ​​a packed container, and my answer, although it was one line at the request, is simply nasty.

0
source share

All Articles