通过非 const 引用参数修改 const 引用参数

Modifying const reference argument via non-const reference argument

考虑以下代码:

#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;
}

此代码在没有任何警告的情况下编译并打印 3。如果我们单独跟踪每个变量,看起来 const-correctness 得到了尊重:c 是非常量,因此将它作为 const ref 作为 a 传递是完全没问题的,并且也作为非常量引用 b,在 f 的主体中我们修改了 b,它是非常量,但不触及 a,它是常量.但是,当 c 被用作 ab 时,af 的主体内被修改,违反了 a 的假设] 是常量,即使没有显式调用 const_cast

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

我的问题是:

However, in main, I pass the same variable, referenced both by a and by b. As f modifies b, it also modifies a, which it supposedly shouldn't

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

Can we really say the above code is const-correct?

是的。您不修改 const 变量。

Other than being confusing to a reader, can the above code be the source of technical problems? Such as undefined behavior, or the compiler performing wrong simplifying assumptions?

不,您的代码是合法的,并且会在所有符合标准的编译器上产生相同的结果。


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

的API角度来看
void f(int const& a, int& b), 

f 承诺 不会通过 a 引用修改任何内容 ,因此尊重 上的 const 正确性=12=]。此外,它 通知 用户 b,另一方面,很可能 被用来修改它寻址的对象; b 可能被记录为 [in, out] 参数,或者只是 [out] 参数,f。如果 b 实际上从未用于修改它所指向的对象,而且没有其他设计理由成为非常量引用,那么,另一方面,可以说是(较弱的)违反f.

的实现者的 const 正确性

用户如何使用或误用这个 API 超出了 f 本身 直接 担心的范围,特别是一旦它 API 设计选择已经做出。然而,任何面向用户的 API 都应该被设计成最小化(鉴于其设计限制)用户射击 him-/herself 脚的风险。例如。在这种情况下,值语义方法 int f(int const& a)int f(int copy_in_a) 可用于为用户构建一个不同且更难滥用的界面。

是的,代码是常量正确的,不,这个特定的代码没有未定义的行为。你在这里写的是一个引用别名的简单案例,归结为pointer aliasing

也就是说,像这样的别名通常是不可取的,因为对于程序员和编译器来说,推理起来确实更复杂。此外,这会阻止某些优化,尤其是处理内存块。

这确实是一种不好的做法,因为很多程序员会(错误地)假设 int const& a 的值在调用过程中确实是常量。考虑

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

看到 b 得到 a+3 的值会非常令人惊讶,但如果 ab 指向同一个变量就会发生这种情况.