为什么std :: for_each是非修改序列操作?

时间:2009-03-19 16:07:56

标签: c++ stl standards foreach

我刚刚在C ++标准中读到std::for_each是一个非修改序列操作,以及findsearch等等。这是否意味着应用于每个元素的函数不应该修改它们?这是为什么?什么可能出错?

这是一个示例代码,其中修改了序列。你能看出它有什么问题吗?

void foo(int & i)
{
    i = 12;
}

int main()
{
    std::vector<int> v;
    v.push_back(0);

    std::for_each(v.begin(), v.end(), foo);
    // v now contains 12
}

我怀疑这只是一个解释问题,但我想对此有所了解。

PS:我知道我可以使用std::transform代替for_each,但这不是重点。

4 个答案:

答案 0 :(得分:20)

很简单,您无法进行可以修改容器结构的更改。这是因为在一般情况下,修改容器会使正在使用的迭代器无效。

只要不改变容器的结构(例如容器中元素的顺序),就可以修改元素。

[加成]


请注意,似乎有一些关于for_each是“非修改”算法的混淆。 Stroustrup在第四版“C ++编程语言,第3版”的勘误表中总结了这种令人困惑的情况。 ( CPL )可以说明for_each是否可以修改序列的元素(http://www.research.att.com/~bs/3rd_printing5.html):

  

for_each()算法被归类为非修改,因为它没有显式修改序列。但是,如果应用于非常量序列for_each(),则可能会更改序列的元素。例如,请参阅11.9中negate()的使用。“ (最近的标准解决方案)。

CPL最初表示传递给for_each的函数或函数对象不允许修改传递给它的元素。但是,CPL是在标准最终确定之前编写并最初发布的,显然对for_each()的限制在最终确定之前已被删除。

另见:

答案 1 :(得分:16)

请参阅this defect report他们说

  

LWG认为标准中没有任何内容禁止修改序列元素的函数对象。问题是for_each是一个名为“非突变算法”的部分,标题可能令人困惑。一份非规范性说明应澄清这一点。

但请注意this one

他们似乎称之为“非修改”,因为for_each本身并不会明确地修改序列的元素。

答案 2 :(得分:6)

我认为“非修改序列操作”意味着此操作不会修改序列。但是操作可以修改容器元素

容器元素和序列的值 - 不同的东西。

答案 3 :(得分:2)

如上所述,for_each被归类为“非突变算法”

STL的“变异”对应是std :: transform。

既然你表示你知道你可以使用std :: transform,那么上面确实成了重点。它可以作为阅读代码的人们的沟通点。

如果我看到std :: for_each,很明显无论foo做什么,它都不会修改容器。

我遵循的指南可以说明:

“如果您希望使用容器的元素来执行不会更改元素的任务,请使用std :: for_each。

如果您希望使用容器的元素以某种系统方式修改元素,或者在将以某种方式更改它们的任务中使用它们,请使用std :: transform。“