繁体   English   中英

在充满指针的std :: vector上使用std :: remove_if

[英]Use std::remove_if on a std::vector filled with pointers

我对std::remove_if函数有一个小问题。 我的程序中某处内存泄漏,我怀疑erase功能以某种方式被破坏。

实际上,我的代码中有这个

std::vector<Object*> v; // Just the constructor to show you
v.erase(std::remove_if(begin(v), end(v), [Foo f](Object *o){
    return o->containsFoo(f);
}), end(v));

但是经过一些研究,这比以前更好吗?

v.erase(std::remove_if(begin(v), end(v), [Foo f](Object *o){
   if(o->containsFoo(f)) {
     delete o;
     return true; 
   }
   return false;
}), end(v));

还是我应该使用其他东西?

您确实应该使用智能指针而不是裸Object* -要么

std::vector<std::unique_ptr<int>>

要么

std::vector<std::shared_ptr<int>>

以适当者为准。 如果使用裸C风格的指针,那么错过关键的delete (或delete两次)太容易了。

尽管如此,很容易看到一种方法泄漏而另一种方法没有泄漏:

#include <algorithm>
#include <vector>

int main(int argc, char **)
{
    std::vector<int*> v{ new int(1), new int(-1) };

    if (argc < 2) {
        // First version
        v.erase(std::remove_if(begin(v), end(v),
                               [](int *o){
                                   return *o < 0;
                               }),
                end(v));
    } else {
        // Second version
        v.erase(std::remove_if(begin(v), end(v),
                               [](int *o){
                                   if (*o < 0) {
                                       delete o;
                                       return true;
                                   }
                                   return false;
                               }),
                end(v));
    }

    // normal cleanup
    for (int *p: v)
        delete p;

}

我在运行时不带参数(调用第一个版本),然后带参数(调用第二个版本)。 看看会发生什么:

g++ -std=c++11 -g -Wall -Wextra 34191606.cpp -o 34191606

valgrind --leak-check=full ./34191606
==16894== HEAP SUMMARY:
==16894==     in use at exit: 72,708 bytes in 2 blocks
==16894==   total heap usage: 4 allocs, 2 frees, 72,728 bytes allocated
==16894== 
==16894== 4 bytes in 1 blocks are definitely lost in loss record 1 of 2
==16894==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16894==    by 0x400881: main (34191606.cpp:6)
==16894== 
==16894== LEAK SUMMARY:
==16894==    definitely lost: 4 bytes in 1 blocks
==16894==    indirectly lost: 0 bytes in 0 blocks
==16894==      possibly lost: 0 bytes in 0 blocks
==16894==    still reachable: 72,704 bytes in 1 blocks
==16894==         suppressed: 0 bytes in 0 blocks
==16894== Reachable blocks (those to which a pointer was found) are not shown.
==16894== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

valgrind --leak-check=full ./34191606 -
==16895== HEAP SUMMARY:
==16895==     in use at exit: 72,704 bytes in 1 blocks
==16895==   total heap usage: 4 allocs, 3 frees, 72,728 bytes allocated
==16895== 
==16895== LEAK SUMMARY:
==16895==    definitely lost: 0 bytes in 0 blocks
==16895==    indirectly lost: 0 bytes in 0 blocks
==16895==      possibly lost: 0 bytes in 0 blocks
==16895==    still reachable: 72,704 bytes in 1 blocks
==16895==         suppressed: 0 bytes in 0 blocks
==16895== Reachable blocks (those to which a pointer was found) are not shown.
==16895== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

请注意,在第一个版本中,您永远不会删除从矢量中删除了指针的对象,并且该对象被报告为泄漏的。 在第二个版本中,没有泄漏的内存。

lambda 更好 ,但是如果我是您(并且由于某些原因您不准备使用std::unique_ptr ),我会这样做:

const auto predicate = [Foo f](Object *o){return !o->containsFoo(f);};
const auto new_end = std::partition(begin(v), end(v), predicate);
std::for_each(new_end, end(v), [](Object *o){delete o;});
v.erase(new_end,end(v));

换一种说法:

  1. 采用 remove_if partition ,将不需要的指针拖到最后
  2. 使用for_each删除所有不需要的对象
  3. 使用erase摆脱(现在无效)不需要的指针。

关键是,在事物四处移动时删除指针是很麻烦的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM