迭代器和标量对象之间的未定义行为有什么区别吗?

Is there any difference with undefined behaviour between iterator and scalar object?

本文关键字:什么 区别 未定义 标量 对象 之间 迭代器      更新时间:2023-10-16

关于求值顺序的主题说,在 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);

当迭代器实际上是一个指针时,此代码将无法编译,而不是导致未定义的行为。