Auto delete object while cycling vector
I have an std::vector of objects and i cycle it calling some methods of the object. One of them will check a particular condition and if needed will delete itsef from the vector. The point is that erasing the element invalidate the iterator and I cannot continue the loop of it. I found boost::shared_ptr and boost::weak_ptr, could these fix the problem deleting the object after calling all methods and after incremented the iterator? If so, how?
EDIT 1
class CPippo
{
public:
void Pippo();
void Pippo2();
}
class CPippoManager
{
public:
void PipppManager();
void RemovePippo(CPippo *pippo);
private:
std::vector<CPippo*> pippoVector;
}
void CPippo::Pippo()
{
...
if (condit开发者_JS百科ion)
{
pippoManager->RemovePippo(this);
}
}
void CPippo::Pippo2()
{
...
}
void CPippoManager::RemovePippo(CPippo *pippo)
{
this->pippoVector.erase(this->pippoVector.begin(), this->pippoVector.end(), pippo);
}
void CPippoManager::PipppManager()
{
for (std::vector<CPippo*>::iterator it = this->pippoVector.begin(); it != this->pippoVector.end; ++it)
{
(*it)->Pippo();
(*it)->Pippo2();
}
}
Never mind what your vector contains - the deletion of managed resources can indeed be left to smart pointers, but the more pressing issue is how to manipulate the container itself.
std::vector
indeed has very poor iterator invalidation: erasing or inserting invalidates all iterators from the erasee/insertee onwards, so you cannot even use the standard earase(it++)
idiom. But neither should you, since erasing from a vector is expensive. The better solution is to use remove/erase and supply a functor that checks the condition for erasure, and then erase everything in one wash:
std::vector<T> v;
v.erase(std::remove_if(v.begin(), v.end(), MyPred), v.end());
Here MyPred
is a predicate that implements your criterion. In C++11 this could be a handy lambda.
If your existing algorithm is too involved, perhaps you can adapt the idea of remove
in your own algorithm and move the to-be-erased object to the back of the vector with swap
, and return the iterator past the last good element at the end of the algorithm. Then you can have your own optional clean-up loop on the range of objects to be deleted, and then call erase
on that range.
As you mention calling a member function you should the erase/remove idiom with std::mem_fun_ref
v.erase(std::remove_if(v.begin(), v.end(), std::mem_fun_ref(&Class::function), v.end()));
To safely delete elements from a vector
you should use the erase-remove idiom.
EDIT: Lots of good responses posted before mine, so thought I'd add a little extra clarification on remove
because it's not immediately obvious how it operates. The remove
algorithm doesn't actually remove anything. All it does is shuffle the container such that all the elements to keep are at the beginning of the container. It then returns an iterator to the end of the kept elements (one past the last element to keep) and that's when you use erase
to actually shorten the container. For example:
vector v;...
v.erase(remove(v.begin(), v.end(), 99), v.end());
will remove all elements in v
with the value 99.
Use the erase-remove idiom:
// You can write a function, a functor or use lambda directly it is up to you!
bool condition(const vector<object>& v);
v.erase( remove_if(v.begin(), v.end(), condition), v.end() );
This is a fantastic article talking about the subject of writing algorithms involving iterators.
You can get a valid iterator back from erase().
for(... it = vec.begin(); it != vec.end(); it++) {
if (condition(it))
it = --vec.erase(it);
}
Of course, you should always use smart pointers to manage resources.
精彩评论