【问题标题】:Auto delete object while cycling vector循环矢量时自动删除对象
【发布时间】:2011-08-28 23:52:07
【问题描述】:

我有一个对象的 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();
    }
}

【问题讨论】:

    标签: c++ boost vector shared-ptr


    【解决方案1】:

    别管你的向量包含什么——托管资源的删除确实可以留给智能指针,但更紧迫的问题是如何操作容器本身。

    std::vector 确实具有非常糟糕的迭代器失效:擦除或插入会使 所有 迭代器从 erasee/insertee 开始失效,因此您甚至不能使用标准的 earase(it++) 成语。但是你也不应该,因为从向量中擦除是昂贵的。更好的解决方案是使用 remove/erase 并提供一个检查擦除条件的函子,然后一次性擦除所有内容:

    std::vector<T> v;
    
    v.erase(std::remove_if(v.begin(), v.end(), MyPred), v.end());
    

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

    如果你现有的算法涉及太多,或许你可以在自己的算法中调整remove的思想,将要擦除的对象移动到swap的向量后面,并返回过去的迭代器算法结束时的最后一个好的元素。然后,您可以对要删除的对象范围进行自己的可选清理循环,然后在该范围内调用erase

    【讨论】:

      【解决方案2】:

      当您提到调用成员函数时,您应该使用 erase/remove idiomstd::mem_fun_ref

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

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

        • 考虑到这个问题,我建议remove_if()。元素删除似乎取决于平等以外的条件。
        【解决方案4】:

        使用擦除删除成语:

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

        【讨论】:

          【解决方案5】:

          你可以从erase() 中得到一个有效的迭代器。

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

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

          【讨论】:

          • 这很酷,很高兴知道,但 it++ 不应该移出 for 循环,++it 应该移入 else 块吗?否则想象你有两个相邻的擦除。
          • @DeadMG 我已经用一个类似于我目前在我的程序中的示例代码编辑了我的问题。使用智能指针的要点是,如果需要,他们可以在最后一次调用第二个函数后删除 CPippo 的实例
          猜你喜欢
          • 2020-10-26
          • 2019-01-09
          • 2015-05-27
          • 2017-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-03
          • 2020-10-26
          相关资源
          最近更新 更多