通过非常量引用参数修改常量引用参数
考虑以下代码:
#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& a
和int& b
。因此,f
不应该修改a
,但它可以修改b
,而且它确实这样做了。 - 然而,在
main
中,我传递了ame变量,由a
和b
引用。当f
修改b
时,它也修改了a
,而它应该不应该修改
此代码编译时没有任何警告,并打印3
。如果我们单独跟踪每个变量,看起来似乎尊重了常量正确性:c
是非常数,因此将其作为const
ref作为a
传递,也作为非常数ref作为b
传递,并在f
的主体内修改b
,这是非常数,但不接触a
,这是常量。但是,当c
同时用作a
和b
时,a
在f
的主体内被修改,这违反了a
是常量的假设,即使没有显式调用const_cast
。
我已经尽可能地简化了这个示例,但是很容易想到不那么明显的用例(例如const
方法作用于非常数引用参数)。
我的问题是:
- 我们真的能说上面的代码是常量正确的吗?
- 上述用例是已知模式吗?这是否被视为不良做法?
- 以上代码除了让读者摸不着头脑,还能成为技术问题的根源吗?例如未定义的行为,或编译器执行错误的简化假设?
解决方案
但是,在main
中,我传递了相同的变量,由a
和b
引用。当f
修改b
时,它也修改了a
,而它应该不应该修改
f
修改b
所指的内容时,不修改a
。它修改了a
所指的内容,但这没有关系,因为b
不是const
。仅当您尝试使用a
修改a
引用的内容时,您才会遇到问题。
我们真的能说上面的代码是常量正确的吗?
是的。您不能修改常量变量。
上述代码除了让读者感到困惑之外,还能成为技术问题的根源吗?例如未定义的行为,或编译器执行错误的简化假设?
否,您的代码是合法的,并且将在所有符合要求的编译器上生成相同的结果。
如果不是
const
,常量引用参数就不会使它引用的内容const
。它所做的一切都会阻止您使用引用来修改对象。只要该对象不是const
本身,另一个指向该对象的指针或引用仍可以使其发生变化。
相关文章