功能参数评估顺序:如果我们传递参考,它是UB吗?

时间:2014-06-12 08:42:38

标签: c++ language-lawyer undefined-behavior

这是未定义的行为:

void feedMeValue(int x, int a) {
  cout << x << " " << a << endl;
}
int main() {
  int a = 2;
  int &ra = a;
  feedMeValue(ra = 3, a); // equivalent to: feedMeValue(a = 3, a) (see note bellow)
  return 0;
}

因为我们可以先调用(3, 2)(3, 3),然后根据所评估的参数进行评估。

但是这个:

void feedMeReference(int x, int const &ref) {
  cout << x << " " << ref << endl;
}

int main() {
  int a = 2;
  int &ra = a;
  feedMeReference(ra = 3, a); // equivalent to: feedMeReference(a = 3, a) (see note bellow)
  return 0;
}

将始终输出3 3,因为第二个参数是引用,并且所有参数都已在函数调用之前进行了求值,因此即使在ra = 3之后评估第二个参数,该函数也会收到在评估时,对a的引用将具有值23,但在函数调用时将始终具有值3

第二个例子是UB吗?重要的是要知道,因为如果编译器检测到未定义的行为,它可以自由地执行任何操作,即使我知道它总会产生相同的结果。


注意:我将离开feedMeReference(ra = 3, a),因为某些答案会引用ra,但您应该注意,如果我们调用feedMeReference(a = 3, a),则更简单的等效问题(更简单,因为我们消除ra这就是我们的问题(第二个参数是参考)。)

1 个答案:

答案 0 :(得分:12)

这是一个有趣的问题。在你的第一个案例中,有 未定义的行为,因为对象被修改了 在没有插入序列点的情况下访问(在语言中 C ++ 03 --- C ++ 11使用不同的语言来表达 一样)。在第二个,没有未定义的行为, 因为用左值初始化引用不能访问 对象,因此唯一的访问权限是ra = 3。 (打电话给 函数建立一个序列点,所以访问 函数在它们和ra = 3之间有一个序列点。)