![](/img/trans.png)
[英]std::remove_if and erase not removing elements from std::vector
[英]std::vector::erase/remove_if resulting in nullptr
我有一个向量std::shared_ptr<MotionTask>
对象,偶尔需要从中清除这些对象。
// this assert passes
assert(std::all_of(d_tasks.begin(), d_tasks.end(),
[](shared_ptr<MotionTask> task) { return bool(task); }));
// Remove any committed tasks for which the corresponding module has completed
d_tasks.erase(
remove_if(
d_tasks.begin(),
d_tasks.end(),
[module](shared_ptr<MotionTask> const& task)
{
return task->isCommitted() && task->getModule() == module;
}
)
);
// this assert fails
assert(std::all_of(d_tasks.begin(), d_tasks.end(),
[](shared_ptr<MotionTask> task) { return bool(task); }));
最终assert
失败,因为在任务向量中,一个为null(假)。
我不了解erase
呼叫如何会使成员无效。 我无法在单元测试中重现此内容。
从上面的代码中可以看到一个解释,如果没有,我该如何调试?
您正在调用单个迭代器std::vector::erase
重载。 您需要两个迭代器版本:
d_tasks.erase(
remove_if(
d_tasks.begin(),
d_tasks.end(),
[module](shared_ptr<MotionTask> const& task)
{
return task->isCommitted() && task->getModule() == module;
}
),
d_tasks.end() // HERE!!
);
单个迭代器版本删除单个元素,而“擦除删除”惯用语则需要删除范围。 这是使用两个迭代器版本实现的。
您的问题是您正在使用vector<T>::erase
的单个迭代器版本,该版本会擦除一个元素。
有两种方法可以解决此问题。 第一种是使用vector<T>::erase
的两个迭代器版本。 第二个是不使用基于迭代器的算法,而是开始编写基于容器的算法。
template<typename Container, typename Lambda>
Container&& remove_if_erase( Container&& container, Lambda&& closure ) {
using std::begin; using std::end;
container.erase(
std::remove_if(
begin(container), end(container), std::forward<Lambda>(closure)
),
end(container)
);
return std::forward<Container>(container);
}
一键执行删除元素和擦除它们的两项操作。 可以编写Traits类,以使其不仅可以使用vector
,还可以使用set
和map
等关联容器。
我发现类似的一个有用的是sort_unique_erase
,它接受一个集合并删除重复项。
通过编写这些基于容器的算法,您的代码将变得更加清晰,并且不易出错,因为您不会在各处重复自己的代码。 许多基于迭代器的技术都会通过简单的输入错误地以意想不到的方式失败:经过测试的基于容器的算法可以可靠地对传入的任何容器进行工作,或者无法编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.