Why is std::for_each a non-modifying sequence oper

2019-01-18 12:47发布

问题:

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.

回答1:

See this defect report they say

The LWG believes that nothing in the standard prohibits function objects that modify the sequence elements. The problem is that for_each is in a secion entitled "nonmutating algorithms", and the title may be confusing. A nonnormative note should clarify that.

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.



回答2:

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 whether for_each can modify the elements of a sequence (http://www.research.att.com/~bs/3rd_printing5.html):

"The for_each() algorithm is classified as nonmodifying because it doesn't explicitly modify a sequence. However, if applied to a non-const sequence for_each() may change the elements of the sequence. For an example, see the use of negate() in 11.9." (recent standards resolution).

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 on for_each() was removed before it was finalized.

See also:

  • http://www.angelikalanger.com/Articles/Cuj/03.ForeachTransform/ForEachTransform.html
  • the C++ LWG defect report mentioned in litb's answer (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#475)


回答3:

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.



回答4:

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."