tags:

views:

104

answers:

5

Hi ,

Should we delete before or after erase. My understanding is both are OK. Is it correct?

In addition, is there any case we won't want to delete the element while erasing it? I believe there must be , otherwise, the erase will be happy to take the responsibility.

std::vector<foo*> bar;
...
for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); itr++)
{
   delete (*itr);  //before OR
   bar.erase(itr);
   delete (*itr);  //after???
}
+4  A: 

Using an iterator to erase an element invalidates the iterator. You should delete the item before it is erased.

You should also use the return value from erase for your next loop iteration.

Paul
good comments in general but can you tell us what is the reason behind "You should delete the item before it is erased". I don't see why this should be the case. In fact I would think that the reverse would be more safe (ie in multithreaded code). The drawback is that you have to keep the value of the pointer in a temporary before calling erase or you won't be able to delete it.I don't see it providing a big advantage so wouldn't recommend it but the way you worded your answer it looks like deleting before is the only way.
n1ck
@n1ck: He was asking between two variants (i.e. before or after). I was simply addressing the question. Of course you could move the pointer over to a temporary, but deleting them in place works just as well for most applications.
Paul
@Paul Harvey: sure, I just said that your wording was maybe not the best as it seems to imply it is the only way. I think the reader should be able to understand but I just wanted to be totally clear that's all.
n1ck
+1  A: 

Doing an erase will invalidate the vector iterator. So *iter will invoke undefined behavior. Hence you need to do the delete after the erase. Also, you can not erase the elements from a vector while iterating through it (because of the same reason, iter becomes invalid so iter++ is invalid). In this case you can remove the erase call from inside the loop and do clear of the vector outside the loop.

Naveen
+6  A: 

"itr" must be used like this;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); )
{
   delete (*itr);
   itr = bar.erase(itr);
}

However, I'd prefer to first delete all elements, and then clear the vector;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); ++itr)
   delete (*itr);
bar.clear();
Viktor Sehr
+1, I would opt for the second version as well: this way I would not have all those shifts of elements within the vector. At the very least if using a loop with erase, backward iteration would be more suited.
Matthieu M.
I agree, but, I am not sure if vector::erase is compatible with a reverse_iterator (to tired to think it thru)
Viktor Sehr
You should use the preferred solution. It is **O(n)** as opposed to **O(n^2)**.
kevlar
+2  A: 

The nature of vector that erasing first element causes entire array to shift forward, to reduce this operation try following:

std::vector<foo*> v1;
//...
while(!v1.empty())
{
    delete v1.back();
    v1.pop_back( );
}

By the way - this method doesn't invalidate any iterators (only on erased items)

Dewfy
+3  A: 

In addition, is there any case we won't want to delete the element while erasing it?

How could the vector possibly know if anyone else needs the objects pointed to? How could it even know that the pointees are stored on the heap? It is perfectly possible to have pointers to static or automatic objects in the vector, or even dangling pointers.

C++0x allows you to express that the vector should own the pointees:

std::vector<std::unique_ptr<foo>> vec;

Now you don't have to manually delete anything. By erasing the unique pointers, their respective pointees are deleted too. Containers of native pointers are very rare in modern C++.

If you don't have a C++0x compiler, you can use std::vector<boost::shared_ptr<foo> > or boost::ptr_vector<foo> instead. Modern compilers supply shared_ptr in the std::tr1 or stdnamespace as well if you #include <memory>.

FredOverflow