为什么 std::for_each 是非修改序列操作?
我刚刚在 C++ 标准中读到 std::for_each
是一个非修改序列操作,还有 find
、search
等等。 这是否意味着应用于每个元素的函数不应修改它们? 这是为什么? 可能会出现什么问题?
这是一个示例代码,其中修改了顺序。 你能看出它有什么问题吗?
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
,但这不是重点。
I just read in the C++ standard that std::for_each
is a non-modifying sequence operation, along with find
, search
and so on. Does that mean that the function applied to each element should not modify them? Why is that? What could possibly go wrong?
Here is a sample code, where the sequence is modified. Can you see anything wrong with it?
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
}
I suspect this to be just an interpretation issue, but I wanted to have your opinion about that.
PS: I know I could use std::transform
instead of for_each
, but that's not the point.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
很简单,您无法进行可能修改容器结构的更改。 这是因为在一般情况下,修改容器可能会使正在使用的迭代器无效。
您可以修改元素,只要它不改变容器的结构(例如容器中元素的顺序)。
[补充]
请注意,对于
for_each
作为“非修改”算法似乎存在一些混淆。 Stroustrup 在《C++ 编程语言,第 3 版》第 4 次印刷的勘误表中总结了这种令人困惑的情况。 (CPL) 对于for_each
是否可以修改序列的元素有这样的说法 (http://www.research.att.com/~bs/3rd_printing5.html):CPL 最初表明传递给
for_each
的函数或函数对象不允许修改传递给它的元素。 然而,CPL 是在标准最终确定之前编写并最初发布的,并且显然在最终确定之前删除了对for_each()
的限制。另请参阅:
Quite simply, you can't make a change that could modify the structure of the container. That's because in the general case, modifying a container can invalidate the iterators being used.
You can modify the element as long as it doesn't change the container's structure (such as the order of elements in the container).
[addition]
Note that there seems to be some confusion about
for_each
being a 'non-modifying' algorithm. This confusing situation is summed up here by Stroustrup in errata for the 4rd Printing of "The C++ Programming Language, 3rd Ed." (CPL) has this to say about whetherfor_each
can modify the elements of a sequence (http://www.research.att.com/~bs/3rd_printing5.html):The CPL originally indicated that the function or function object passed to
for_each
was not permitted to modify the element passed to it. However, the CPL was written and originally published before the standard was finalized, and apparently this restriction onfor_each()
was removed before it was finalized.See also:
他们说,请参阅此缺陷报告
但还要注意这个。
他们似乎称其为“非修改”,因为 for_each 本身不会显式修改序列的元素。
See this defect report they say
But also note this one.
They seem to call it "non-modifying" because for_each itself does not exlicitly modify the elements of the sequence.
我认为“非修改序列操作”意味着该操作不修改序列。 但操作可以修改容器元素。
容器元素的值和序列 - 不同的东西。
I think "Non-modifying sequence operations" mean that this operation not modify sequence. But operation could modify container elements.
Value of container elements and sequence - different things.
正如上面 litb 所指出的,for_each 被归类为“非变异算法”,
STL 的“变异”对应物是 std::transform。
既然您表示您知道可以使用 std::transform,那么上述内容确实成为了重点。 它是与阅读你的代码的人的沟通点。
如果我看到 std::for_each,很明显无论 foo 做什么,它都不会修改容器。
我遵循的准则可以这样表述:
“如果您希望使用容器的元素来执行某些不更改元素的任务,请使用 std::for_each。
如果您希望使用容器的元素来修改元素以某种系统的方式或在以某种方式改变它们的任务中使用它们,请使用 std::transform。”
As litb indicated above, the for_each is classified as a 'nonmutating algorithm'
STL's 'mutating' counterpart to that is std::transform.
Since you indicated you know you can use std::transform, the above does indeed become the point. It serves as a point of communication to folks who read your code.
If I see std::for_each, it is clear that whatever foo does, it won't modify the container.
The guideline I follow can be stated:
"If you wish to use the elements of a container to do some task that does not change the elements, use std::for_each.
If you wish to use the elements of a container to modify the elements in some systemic manner or use them in a task that will change them in some manner, use std::transform."