有状态函子和STL:未定义行为

| 我正在关注此功能对象教程 复制副本如下: 我无法理解以下内容: 谓词应始终实现为无状态函数对象,以避免意外结果。无法保证算法在内部复制谓词的频率。因此,将谓词实现为有状态函数对象可能会产生未执行的结果。 示例如下:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

class predicate
{
public:
   predicate(int condition) :
      condition_(condition), state_(0) {}
   bool operator()(int) { return ++state_ == condition_; }

private:
   int condition_;
   int state_;
};

int main()
{
   std::vector<int> vec;
   vec.push_back(1);
   vec.push_back(2);
   vec.push_back(3);
   vec.push_back(4);
   vec.push_back(5);

   predicate p(2);
   std::vector<int>::iterator pos =
      std::remove_if(vec.begin(), vec.end(), p);
   vec.erase(pos, v.end());

   std::copy(vec.begin(), vec.end(),
             std::ostream_iterator<int>(std::cout, \" \"));

   return 0;
}
如果我正确理解(阅读)它,它正在尝试删除向量中标记为2的元素。 remove_if算法返回容器的新末端并尝试擦除所有末端。 输出:
1 3 5
显然,不仅删除了第二个元素,而且删除了第四个元素。好奇心的答案很简单,就是所使用的算法'remove_if \'在执行期间在内部复制谓词。并且此内部副本将创建一个包含其原始状态的新谓词对象。 尽管我可以看清正在发生的情况,但我无法想象幕后发生的情况,这些情况实际上甚至标记了第四个要移到容器末端的元素。这与单次通过或多次通过的算法有关吗? (如果有人能指出正确的方向,我也将不胜感激) 顺便说一句,如果我评论擦除并记下输出。
1 3 5 4 5
是什么导致容器损坏?     
已邀请:
该报价的含义应从表面上看。对于大多数STL算法,您不应将谓词函子实现为具有可观察状态(又称为“副作用”),因为: 未定义容器上的迭代顺序, 该算法可以自由复制仿函数, 该算法可能取决于无状态性,以便不破坏容器中的内容或崩溃。 对自己执行此操作的最简单方法是将
operator()
定义为
const
。 有ѭ5之类的例外情况,以上均不适用。您可以在这里自由使用有状态函子。有关更多信息,请参见这篇出色的文章:http://drdobbs.com/cpp/184403769。 在后台,您的STL实现的作者可以自由地以他们喜欢的任何方式编写
remove_if
(以及其他算法),只要它符合标准所规定的要求即可。除了承认它是未定义的之外,没有真正的原因要过多担心确切的原因。如果您想了解细节,我将只看一下您正在使用的STL实现中的
remove_if
代码。 至于你的旁注;这不是“腐败”,而只是“ 6”如何工作的产物(即使对于有效的谓词,也会发生)。唯一的要求是
pos
左边的所有元素都是有效的(因为将保留它们)。从
pos
开始不存在什么元素的要求(请参见此处)。 (Scott Meyers的“有效STL”的第32章很好地解释了为什么
remove_if
(依此类推)的行为如此)。     

要回复问题请先登录注册