tags:

views:

6877

answers:

9

What is the shortest chunk of C++ you can come up with to safely clean up a vector or 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.

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

std::for_each( foo_list.begin(), foo_list.end(), delete_ptr<Foo>() );
John Dibling
+3  A: 
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();
Douglas Leeder
+4  A: 

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?

Charles Bailey
The functor approach may not win for brevity, but that's not much of a prize. By using a functor you avoid having to write your own for loop, which is a source of many defects in software.
John Dibling
The question specifically asked about "shortest". I had no idea that manual for loops were a major source of defects, can you provide a reference? If a member of my team had a problem writing a bug free for loop, I'd rather not let him loose on a functor solution.
Charles Bailey
A: 
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();
Assaf Lavie
+8  A: 

std::list<T*>:

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

std::vector<T*>:

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(); }
Johannes Schaub - litb
Technically correct, but it gets a lot longer if you use more common brace and indenting conventions.
Mark Ransom
read it from left to right: While foo is not empty, delete the front of foo, and pop the front of foo :p newlines would only get into the way :/
Johannes Schaub - litb
I'd recommend against using the comma (sequence) operator. Too many C++ devs have no idea what it does, and will mistake it for a semicolon.
Kristopher Johnson
+7  A: 

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.

Mark Ransom
i second you opinion
Yogesh Arora
+3  A: 

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.

Greg Rogers
+10  A: 

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?

Mr.Ree
I like it. I wrote a function template instead, but the remove_if idea is nice.
twk
achieves the purpose but seems very hacky...
Yogesh Arora
A: 

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

http://www.cplusplus.com/reference/std/memory/allocator/

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.

Jeremy Cowles