The topic about evaluation order says that following code leads to undefined behavior until C++17:
a[i] = i++;
This happens due to unspecified order while evaluating left and right parts of the assignment expression.
C++14 standard 1.9/15 says:
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is undefined.
But what if we use std::vector
and its iterator
object instead of scalar object i
?
std::vector<int> v = {1, 2};
auto it = v.begin();
*it = *it++; // UB?
Is there undefined behaviour (until c++17) or not?
In situations when an iterator is a class, the behavior is well defined in all versions of the standard, assuming that it++
points to a valid location inside its container (which in your example it does).
C++ translates *it++
to this sequence of two function calls:
it.operator++(0).operator*();
Function calls introduce sequencing, so all side effects of the actual ++
invoked inside operator++
on the primitive used as an iterator's implementation (probably, a raw pointer) must complete before the function exit.
However, iterators are not required to be classes: they could be pointers, too:
struct foo {
typedef int* iterator;
iterator begin() { return data; }
private:
int data[10];
};
The code looks the same, and it continues to compile, but now the behavior is undefined:
foo f;
auto it = f.begin();
*it = *it++; // <<== This is UB
You can guard against this by invoking ++
as a member function:
std::vector<int> v = {1, 2};
auto it = v.begin();
*it = *it.operator++(0);
When the iterator is actually a pointer, this code will fail to compile, rather than causing undefined behavior.