C++14 和 C++17 赋值运算符的奇怪差异

Bla*_*cic 5 c++ stdvector assignment-operator c++14 c++17

我有以下代码:

#include <vector>
#include <iostream>

std::vector <int> a;

int append(){
  a.emplace_back(0);
  return 10;
}

int main(){
  a = {0};
  a[0] = append();
  std::cout << a[0] << '\n';
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

该函数append()的副作用是将向量大小增加一。由于向量的工作方式,当超出其容量时,可能会触发其内存的重新分配。

因此,在执行 时a[0] = append(),如果发生重新分配,则 thena[0]无效并指向向量的旧内存。因此,您可以预期向量最终会变为,{0, 0}而不是{10, 0},因为它分配给旧向量a[0]而不是新向量。

让我感到困惑的是,这种行为在 C++14 和 C++17 之间发生了变化。

在 C++14 上,程序将打印 0。在 C++17 上,它将打印 10,这意味着a[0]实际上分配了 10。所以,我有以下问题,但我找不到答案:

  • C++17 是否a[0]在评估赋值表达式的 RHS 之后评估 的内存地址?C++14 之前是否对此进行了评估,这就是它发生变化的原因?
  • 这是 C++17 中修复的错误吗?标准发生了什么变化?
  • 使用 C++14 或 C++11 时,是否有一种干净的方法可以使此分配的行为类似于 C++17 中的行为?

qz-*_*qz- 7

正如注释中指出的,由于 C++求值顺序规则,此代码是 C++17 之前的 UB 。基本问题:运算顺序不是求值顺序。甚至类似的东西x++ + x++也是UB。

在 C++17 中,赋值的排序规则发生了变化:

  1. 在每个简单赋值表达式 E1=E2 和每个复合赋值表达式 E1@=E2 中,E2 的每个值计算和副作用都排序在 E1 的每个值计算和副作用之前