循环向量时自动删除对象

时间:2011-08-28 23:52:07

标签: c++ boost vector shared-ptr

我有一个std :: vector对象,我循环调用该对象的一些方法。其中一个将检查特定条件,如果需要将从向量中删除它。关键是擦除元素会使迭代器失效,我无法继续它的循环。我找到了boost :: shared_ptr和boost :: weak_ptr,这些可以修复在调用所有方法之后删除对象并在增加迭代器之后的问题吗?如果是这样,怎么样?

编辑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();
    }
}

5 个答案:

答案 0 :(得分:2)

不要介意你的矢量包含什么 - 删除托管资源确实可以留给智能指针,但更紧迫的问题是如何操纵容器本身。

std::vector确实有很差的迭代器失效:从erasee / insertee开始擦除或插入所有迭代器无效,因此你甚至无法使用标准的earase(it++)成语。但是你也不应该,因为从矢量中删除是昂贵的。更好的解决方案是使用删除/擦除并提供一个函数来检查擦除条件,然后在一次清洗中删除所有内容:

std::vector<T> v;

v.erase(std::remove_if(v.begin(), v.end(), MyPred), v.end());

此处MyPred是一个实现您的标准的谓词。在C ++ 11中,这可能是一个方便的lambda。

如果您现有的算法过于复杂,也许您可​​以在自己的算法中调整remove的概念,并使用swap将待删除的对象移动到向量的背面,并且将迭代器返回算法末尾的最后一个好元素。然后,您可以在要删除的对象范围上拥有自己的可选清理循环,然后在该范围内调用erase

答案 1 :(得分:2)

当你提到调用成员函数时,erase/remove idiom应该std::mem_fun_ref

v.erase(std::remove_if(v.begin(), v.end(), std::mem_fun_ref(&Class::function), v.end()));

答案 2 :(得分:2)

要安全删除vector中的元素,您应该使用erase-remove idiom

编辑:我之前发布了很多好的回复,所以我想在remove上添加一些额外的说明,因为它的运作方式并不是很明显。 remove算法实际上并没有删除任何内容。它所做的只是将容器洗牌,使得所有要保留的元素都在容器的开头。然后它将一个迭代器返回到保留元素的末尾(一个超过要保留的最后一个元素),当你使用erase来实际缩短容器时。例如:

vector v;... v.erase(remove(v.begin(), v.end(), 99), v.end());

将删除v中值为99的所有元素。

答案 3 :(得分:1)

使用擦除删除习语:

// 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

答案 4 :(得分:1)

您可以从erase()获取有效的迭代器。

for(... it = vec.begin(); it != vec.end(); it++) {
    if (condition(it))
        it = --vec.erase(it);
}

当然,您应该始终使用智能指针来管理资源。