Search code examples
c++boostvectorshared-ptr

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 (condition)
    {
        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();
    }
}

Solution

  • 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.