在 C++ 中: const 引用是指“只读视图”还是需要被引用对象的不变性?

Posted

技术标签:

【中文标题】在 C++ 中: const 引用是指“只读视图”还是需要被引用对象的不变性?【英文标题】:in C++: Is const reference means "read-only view of" or it requires immutability of object being referenced? 【发布时间】:2014-03-16 12:31:12 【问题描述】:

问题可以通过例子表述如下:这段代码的sn-p是否有效?

int a = 1;
const int& ca = a;
++a; //< Q: Is this valid?
cout << "a: " << a << endl;
cout << "ca: " << ca << endl; // Q: Is it guaranteed to output "2"? Is it valid at all?

使用 MSVC 和 MinGW,上面的 sn-p 按预期工作:如果我在后面查询 ca,它会返回 2(即它被非常量引用更改)。但问题是:如何从标准的角度考虑这种情况?可以更改对象,我们有 const 引用(或者例如,我们必须将 ca 定义为 const volatile 引用,以便 sn-p 正确)?

所以,如果上面的 sn-p 是正确的,那么这意味着 const 引用不能保证被引用的对象是常量。它只禁止我们通过给定的引用来改变它,即建立被引用对象的“只读”视图。这是正确的吗?

编辑: 感谢所有回答我问题的人。答案说明了事情,这对我来说似乎很自然。但是,我真的很感激有人参考 c++ 标准中的特定条款。

编辑2: 扩展了原始示例以使问题的概念更加清晰。

编辑3 另一个例子,最初出现在我对 Mats Peterson 答案的评论中。

class MyClass 
public:
    // ...
    const X& getX() const;
    void modifyX();
private:
    X m_x;
;

void someFun() 
    //...
    MyClass myObj = ... // non-cons
    const X& x = myObj.getX();
    // ...
    myObj.modifyX(); // Q: is `x` guaranteed to track value of x stored in myObj here?

问题是:在优化期间是否允许编译器删除x 变量的更新,因为它被声明为const?例如。如果类型 Xbool,则按值存储 x 比按引用存储提供更好的性能和更少的内存消耗。

换句话说:如果后续调用myObj 的方法修改了该内部值,是否保证局部变量x 将跟踪myObj 内部相应内部值的变化?

【问题讨论】:

"这意味着,const 引用并不能保证被引用的对象是常量。它只是禁止我们通过给定的引用来改变它,即建立被引用对象的“只读”视图" 这与我回答的评论中的示例仍有很大不同。在某些可能的情况下,要弄清楚到底发生了什么是极其复杂的。 我会说在上面的代码中修改a是绝对合法的。 我记得有一种奇怪的感觉,必须同步来自 const 引用的读取。我知道只有当 ref 引用的对象最初声明为 const 时,抛弃 const 才是 UB。 【参考方案1】:

这是有效的代码,因为a 不是constconst 引用意味着您不能通过引用修改所引用的对象。

【讨论】:

【参考方案2】:

在这种特殊情况下,您所做的只是创建一个const 的引用——这意味着ca 不能修改它所引用的值(在这种情况下为a)。

一种常见的用法是将 const 引用传递给函数:

void foo(const int& cr)

   ... use cr ... 

这表明虽然该值是一个引用,但函数foo 不会改变cr 中的值。使用可修改的int 变量或什至无法引用的变量(例如foo(4); - 值 4 只是一个常量,因此不能真正用作参考)调用此函数是完全有效的- 编译器将通过创建一个临时 int 变量来“修复”这个问题,并将引用传递给它)。

当然,这更常用于比int 更复杂的类型——例如std::stringstd::vector。在这种情况下,主要原因是避免复制值,而不是“我想要参考”。

【讨论】:

更相关的是以下示例的分析师:const X&amp; x = myObj.getConstX(); myObj.modifyX();。问题是:本地x是否可以保证跟踪myObj的相应内部数据的变化?当然mhObj 不是常量。 嗯,这是一个完全不同的问题,可能真的应该作为一个单独的问题提出。我不知道标准是否规定了这一点。可以很容易地看出,如果标准没有要求,编译器可以优化 x 的读取,并且只使用以前读取的值。 是的,完全正确。这不是另一个问题,这正是我从一开始就提出的问题。虽然,现在我明白了,我最初的例子并没有清楚地突出主要思想。我会努力解决的。 使用 g++ 4.6.3 和 clang++ 的一个非常简单的测试表明这些东西似乎没有得到优化。换句话说,对象内部的变化确实会改变引用中的实际值。这是你所期望的,至少是这样的。 @DmitrySemikin:不,这是一个不同的问题。 :) 引用总是精确地“跟踪”所指对象,但是是否在对同一对象的两次单独读取中获得正确的结果,而两者之间的写入在当前翻译单元中可能不可见,这是一个完全不同的问题(而不是与参考文献本身相关)。以volatile 为例。【参考方案3】:

因为引用只是对变量的另一个名称,而不是对象本身,是的,在您显示的 sn-p 中,它可以被认为是只读引用。引用提供的代码只能访问它,但它不保证对象本身不会在程序的其他地方被更改。

【讨论】:

以上是关于在 C++ 中: const 引用是指“只读视图”还是需要被引用对象的不变性?的主要内容,如果未能解决你的问题,请参考以下文章

在 const 成员函数中返回 C++ 引用

C++中的const关键字深入理解(关于引用指针顶层const)

C++,在函数中采用 const lvalue 和 rvalue 引用

C++ 成员引用基类型'Vertex *const'不是结构或联合

在 C++ 中,通过引用传递 const long double 是不是很好?

const 引用字段作为 C++ 类中的只读属性