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