【问题标题】:How do delete items in a vector if using remove_if and items are pointers to objects?如果使用 remove_if 并且项目是指向对象的指针,如何删除向量中的项目?
【发布时间】:2011-12-19 13:28:20
【问题描述】:

我担心通过执行以下操作会遇到内存泄漏问题:

(示例代码)

class myItem //random container stuff mostly. All primatives.
{
    int index;
    char* name;
    int val1;
    int val2;
};

class vecList
{

    vector< myitem* > *myVec;

    void delete()
    { 
        MyVec->erase(std::remove_if(myVec->begin(), MyVec->end(), IsMarkedToDelete), MyVec->end()); //leak here?
    }
};

如果是指针,擦除不会释放内存,对吧?如果我没有使用 remove_if,我可以在销毁指针之前调用 delete。在这种情况下我该怎么做?智能指针?我不想用它们重新实现所有东西,我也不想添加 boost 库。

谢谢!

【问题讨论】:

  • 这取决于myitem 的创建方式以及myitem 究竟包含什么...
  • 一般 C++ 建议:如果您使用的是原始指针,那么您做错了。 (这不是绝对的,但是那些知道自己在做什么的人知道什么时候可以忽略这个建议。)
  • @Kerrek:使用小型nonowning_ptr 包装类,它本质上是一个原始指针,但具有描述性名称,您可以完全避免使用原始指针。 :)
  • @Xeo:是的。当您这样做时,您可能已经知道如何执行 OP 要求的操作 :-)
  • 安全地销毁由 STL 指针容器引用的对象很棘手,因为 STL 迭代器操作可能会引发异常:stackoverflow.com/questions/7902452/…

标签: c++ memory-leaks vector erase remove-if


【解决方案1】:

您可以在 IsMarkedToDelete 函数返回 true 时删除该项目。

【讨论】:

  • 这实际上是个好主意。我将首先看看我是否可以重新编写代码以不使用指向项目的指针,但如果事实证明这是不可能的,这可能是要走的路(假设这样做没有问题?)
【解决方案2】:

如果指向对象的唯一指针在向量中,那么您已经 只要您致电remove_if,就会泄漏内存。 remove_if 移动 您正在保留的指针,但它没有说明任何内容 它返回的迭代器后面的值。因此,如果你有东西 比如[a, b, c, d](其中ab等代表不同的指针), 然后在e = remove_if( v.begin(), v.end(), matches(b) ) 之后,你的 矢量可能(并且可能会)看起来像[a, c, d, d],带有e 指向第二个d,所有b 的痕迹都永远丢失了。

显而易见的解决方案是在vector 中使用shared_ptr;这 将确保最终从 vector 中删除的任何指针 将被删除。如果做不到这一点,您可以使用两个通行证:第一个通行证 成为for_each 类似于:

struct DeleteIfCondition
{
    void operator()( ObjectType* &ptr ) const
    {
        if ( condition( *ptr ) ) {
            ObjectType* tmp = ptr;
            ptr = NULL;
            delete tmp;
        }
    }
};

std::for_each( v.begin(), v.end(), DeleteIfCondition() );

作为功能对象,后跟:

v.erase( std::remove( v.begin(), v.end(), NULL ), v.end() );

【讨论】:

  • 您的仿函数是关于我将用于我的答案的,只需添加 bool 返回。 :)
【解决方案3】:

你可以使用remove_if,然后for_each从返回值一直到结束,然后擦除。当然,这会使您的代码更长一些。如果您的代码同意,另一种可能性是存储 shared_ptr 指针。

正如本杰明指出的那样,以上是一个直截了当的谎言,所以你只剩下“另一种可能性”。

【讨论】:

  • 使用 for_each 会有什么帮助?
  • std::for_each(rif=std::remove_if(...),YourVec-&gt;end(),[](myitem* i){delete i;}); std::erase(rif,YourVec-&gt;end()); — 为了简洁起见,我说 c++11,我相信,如果你的项目中没有它,你必须在 c++ 中引入删除函数。
  • 这假定 remove_if 进行交换,将删除的项目移动到末尾。它没有做出这样的承诺。
  • 那么,我只剩下使用 shared_ptrs 了吗?我的代码线程非常多。这不会引起一些问题吗?
  • std::partition 如果要对序列进行分区,则可用。
【解决方案4】:

你可以使用这个功能:

template<typename T, typename TESTFN>
void delete_if(std::vector<T*>& vec, TESTFN&& predicate)
{
   auto it = remove_if(vec.begin(), vec.end(), [&](T* item) {
      if (predicate(item)) {
         delete item;
         return true;
      }
      return false;
   });
   vec.erase(it, vec.end());
}

例如:

delete_if(MyVec, [](T* item) { return item->index == 5; });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-05
    • 2013-05-28
    • 1970-01-01
    • 2020-06-24
    • 2019-12-02
    • 1970-01-01
    相关资源
    最近更新 更多