话题 关于评估顺序说,以下代码导致未定义的行为,直到C ++ 17:
a[i] = i++;
这是由于在评估赋值表达式的左右部分时未指定的顺序而发生的。
C ++ 14标准1.9 / 15说:
如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,并且它们不是潜在的并发(1.10),则行为未定义。
但是如果我们使用它会怎样 std::vector
和它的 iterator
对象而不是标量对象 i
?
std::vector<int> v = {1, 2};
auto it = v.begin();
*it = *it++; // UB?
是否存在未定义的行为(直到c ++ 17)?
在迭代器是一个类的情况下,行为在标准的所有版本中都有明确定义,假设如此 it++
指向其容器内的有效位置(在您的示例中它确实如此)。
C ++翻译 *it++
这两个函数调用的序列:
it.operator++(0).operator*();
函数调用引入了排序,因此实际的所有副作用 ++
在里面调用 operator++
用作迭代器实现的原语(可能是原始指针)必须在函数退出之前完成。
但是,迭代器不需要是类:它们也可以是指针:
struct foo {
typedef int* iterator;
iterator begin() { return data; }
private:
int data[10];
};
代码看起来一样,并且继续编译,但现在行为是未定义的:
foo f;
auto it = f.begin();
*it = *it++; // <<== This is UB
您可以通过调用来防范这种情况 ++
作为会员功能:
std::vector<int> v = {1, 2};
auto it = v.begin();
*it = *it.operator++(0);
当迭代器实际上是一个指针时,此代码将无法编译,而不是导致未定义的行为。