1

我有一个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失败,因为在任务向量中,一个为空(假)。

我不明白调用如何erase使成员无效。我无法在单元测试中重现这一点。

从上面的代码中是否可以观察到解释,如果没有,我可以尝试调试什么?

4

2 回答 2

7

您正在调用单个迭代器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!!
);

单迭代器版本删除单个元素,而擦除删除习惯用法需要删除范围。这是使用两个迭代器版本实现的。

于 2013-06-09T23:25:22.657 回答
2

您的问题是您使用的是单个迭代器版本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);
}

它执行删除元素和一次性擦除它们的两个操作。可以编写特征类以使其不仅可以使用vector,还可以使用 和 等关联set容器map

我发现一个类似的有用的是sort_unique_erase,它需要一个集合并删除重复项。

通过编写这种基于容器的算法,您的代码会变得更清晰且不易出错,因为您不会到处重复自己。许多基于迭代器的技术会因一个简单的错字而以意想不到的方式静默失败:经过测试的基于容器的算法可以可靠地在传入的任何容器上工作,或者无法编译。

于 2013-06-09T23:38:08.687 回答