Cleaning up an STL list/vector of pointers

C++ListVectorStl

C++ Problem Overview


What is the shortest chunk of C++ you can come up with to safely clean up a std::vector or std::list of pointers? (assuming you have to call delete on the pointers?)

list<Foo*> foo_list;

I'd rather not use Boost or wrap my pointers with smart pointers.

C++ Solutions


Solution 1 - C++

For std::list<T*> use:

while(!foo.empty()) delete foo.front(), foo.pop_front();

For std::vector<T*> use:

while(!bar.empty()) delete bar.back(), bar.pop_back();

Not sure why i took front instead of back for std::list above. I guess it's the feeling that it's faster. But actually both are constant time :). Anyway wrap it into a function and have fun:

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }

Solution 2 - C++

Since we are throwing down the gauntlet here... "Shortest chunk of C++"

static bool deleteAll( Foo * theElement ) { delete theElement; return true; }

foo_list . remove_if ( deleteAll );

I think we can trust the folks who came up with STL to have efficient algorithms. Why reinvent the wheel?

Solution 3 - C++

for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();

Solution 4 - C++

If you allow C++11, you can do a very short version of Douglas Leeder's answer:

for(auto &it:foo_list) delete it; foo_list.clear();

Solution 5 - C++

It's really dangerous to rely on code outside of the container to delete your pointers. What happens when the container is destroyed due to a thrown exception, for example?

I know you said you don't like boost, but please consider the boost pointer containers.

Solution 6 - C++

template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
   bool operator()(T*pT) const { delete pT; return true; }
};

std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());

Solution 7 - C++

I'm not sure that the functor approach wins for brevity here.

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;

I'd usually advise against this, though. Wrapping the pointers in smart pointers or using a specialist pointer container is, in general, going to be more robust. There are lots of ways that items can be removed from a list ( various flavours of erase, clear, destruction of the list, assignment via an iterator into the list, etc. ). Can you guarantee to catch them all?

Solution 8 - C++

The following hack deletes the pointers when your list goes out of scope using RAII or if you call list::clear().

template <typename T>
class Deleter {
public:
  Deleter(T* pointer) : pointer_(pointer) { }
  Deleter(const Deleter& deleter) {
    Deleter* d = const_cast<Deleter*>(&deleter);
    pointer_ = d->pointer_;
    d->pointer_ = 0;
  }
  ~Deleter() { delete pointer_; }
  T* pointer_;
};

Example:

std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();

Solution 9 - C++

At least for a list, iterating and deleting, then calling clear at the end is a bit inneficient since it involves traversing the list twice, when you really only have to do it once. Here is a little better way:

for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
    list<Foo*>::iterator tmp(i++);
    delete *tmp;
    foo_list.erase(tmp);
}

That said, your compiler may be smart enough to loop combine the two anyways, depending on how list::clear is implemented.

Solution 10 - C++

Actually, I believe the STD library provides a direct method of managing memory in the form of the allocator class

You can extend the basic allocator's deallocate() method to automatically delete the members of any container.

I /think/ this is the type of thing it's intended for.

Solution 11 - C++

for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();

There's a small reason why you would not want to do this - you're effectively iterating over the list twice.

std::list<>::clear is linear in complexity; it removes and destroys one element at a time within a loop.

Taking the above into consideration the simplest to read solution in my opinion is:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}

Solution 12 - C++

Since C++11:

std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());

Or, if you are writing templated code and want to avoid specifying a concrete type:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());

Which (since C++14) can be shortened as:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());

Solution 13 - C++

void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );

Solution 14 - C++

for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();

Solution 15 - C++

This seems cleanest imo, but your c++ version must support this type of iteration (I believe anything including or ahead of c++0x will work):

for (Object *i : container) delete i;    
container.clear();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontwkView Question on Stackoverflow
Solution 1 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 2 - C++Mr.ReeView Answer on Stackoverflow
Solution 3 - C++Douglas LeederView Answer on Stackoverflow
Solution 4 - C++AdisakView Answer on Stackoverflow
Solution 5 - C++Mark RansomView Answer on Stackoverflow
Solution 6 - C++John DiblingView Answer on Stackoverflow
Solution 7 - C++CB BaileyView Answer on Stackoverflow
Solution 8 - C++LinoliumzView Answer on Stackoverflow
Solution 9 - C++Greg RogersView Answer on Stackoverflow
Solution 10 - C++Jeremy CowlesView Answer on Stackoverflow
Solution 11 - C++HeeroView Answer on Stackoverflow
Solution 12 - C++ostappusView Answer on Stackoverflow
Solution 13 - C++kendotwillView Answer on Stackoverflow
Solution 14 - C++Assaf LavieView Answer on Stackoverflow
Solution 15 - C++CompEng88View Answer on Stackoverflow