对填充了指针的std::向量使用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));
换句话说:
- 使用
- 使用
for_each
删除所有不需要的对象 - 使用
erase
来清除(现在无效的)不需要的指针
remove_if
partition
将不需要的指针拖到末尾
关键是,在事物移动时删除指针是很麻烦的。
相关文章:
- std::remove() 按预期处理文字,但不能与取消引用的迭代器一起工作
- 使用容器中元素的别名删除带有 std::list::remove 的元素是否正确?
- C++代码"x.erase(std::remove(x.begin(), x.end(), ), x.end())"是如何工作的?
- std::remove, std::move(range) and moved-from elements
- 在不同类型的向量上使用 std::remove 的不同结果
- 为什么 std::remove 不删除数组的最后一个元素
- std::remove 和 std::remove_if 设计的稳定性是否失败
- std::unordered_map:渐近{search,insert,remove}性能取决于密钥的大小和数据类型
- std::remove 不起作用
- 为什么std::whatever::erase()是一个方法,std::remove()是独立函数
- std::erase 和 std::remove 组合以删除特定元素不适用于特定示例
- std::remove函数中的转换错误
- 使用 std::erase 和 std::remove 从矢量中删除元素,不使用自定义结构作为值
- vector.erase 和 std::remove 在自定义向量上
- 需要了解 std::remove with vector.erase
- 为什么std::remove不能和std::set一起工作
- 如何为std::list重载std::remove
- std::remove导致编译错误
- Std::remove不是从Std::vector中移除
- 为什么std::remove取迭代器的const版本