通过非常量引用参数修改常量引用参数

考虑以下代码:

#include <iostream>

void f(int const& a, int& b)
{
  b = a+1;
}

int main() {
  int c=2;
  f(c,c);
  std::cout << c << std::endl;
}
  • 函数f有两个引用参数:int const& aint& b。因此,f不应该修改a,但它可以修改b,而且它确实这样做了。
  • 然而,在main中,我传递了ame变量,由ab引用。当f修改b时,它也修改了a,而它应该不应该修改

此代码编译时没有任何警告,并打印3。如果我们单独跟踪每个变量,看起来似乎尊重了常量正确性:c是非常数,因此将其作为constref作为a传递,也作为非常数ref作为b传递,并在f的主体内修改b,这是非常数,但不接触a,这是常量。但是,当c同时用作ab时,af的主体内被修改,这违反了a是常量的假设,即使没有显式调用const_cast

我已经尽可能地简化了这个示例,但是很容易想到不那么明显的用例(例如const方法作用于非常数引用参数)。

我的问题是:

  • 我们真的能说上面的代码是常量正确的吗?
  • 上述用例是已知模式吗?这是否被视为不良做法?
  • 以上代码除了让读者摸不着头脑,还能成为技术问题的根源吗?例如未定义的行为,或编译器执行错误的简化假设?

解决方案

但是,在main中,我传递了相同的变量,由ab引用。当f修改b时,它也修改了a,而它应该不应该修改

f修改b所指的内容时,不修改a。它修改了a所指的内容,但这没有关系,因为b不是const。仅当您尝试使用a修改a引用的内容时,您才会遇到问题。

我们真的能说上面的代码是常量正确的吗?

是的。您不能修改常量变量。

上述代码除了让读者感到困惑之外,还能成为技术问题的根源吗?例如未定义的行为,或编译器执行错误的简化假设?

否,您的代码是合法的,并且将在所有符合要求的编译器上生成相同的结果。


如果不是const,常量引用参数就不会使它引用的内容const。它所做的一切都会阻止您使用引用来修改对象。只要该对象不是const本身,另一个指向该对象的指针或引用仍可以使其发生变化。

相关文章