C++ 常量引用非常量对象和非常量引用非常量对象之间的区别

Posted

技术标签:

【中文标题】C++ 常量引用非常量对象和非常量引用非常量对象之间的区别【英文标题】:C++ Difference Between Const Reference to Non Const Object and Non Const Reference to Non Const Object 【发布时间】:2019-02-05 18:43:32 【问题描述】:

如果引用的对象不是 const 对象,则引用的“const”关键字的目的是什么? r1 和 r2 的作用(下)有什么区别?

int i = 42; // non const object
const int &r1 = i; // const reference to non const object

int j = 25; // non const object
int &r2 = j; // non const reference to non const object

这是 CPP Primer 5th 的引述:

“C++ 程序员倾向于将短语“reference to const”缩写为 “常量参考。”这个缩写是有道理的——如果你记得它 是一个缩写。 从技术上讲,没有 const 引用。参考不是 对象,因此我们不能将引用本身设为 const。确实,因为有 没有办法让引用指向不同的对象,在某种意义上所有 引用是常量。引用是指 const 还是 nonconst 类型影响我们可以使用该引用做什么,而不是我们是否可以改变 引用本身的绑定。”

我认为这意味着当引用非 const 对象时将引用设为“const”绝对没有任何作用。我们不妨在定义那个引用时去掉那个 const 关键字。

在此询问此问题以进行确认。

编辑:看起来我最初的猜想是错误的。我现在明白了对非 const 对象的 const 引用确实有一个目的:防止引用修改对象。非 const 对象仍然可以通过其他方式修改,但不能通过此 const 引用。

谢谢大家。

【问题讨论】:

“我认为这意味着当引用非 const 对象时将引用设为“const”绝对没有任何作用。”你想错了 【参考方案1】:

“如果引用的对象不是 const 对象,引用的“const”关键字的用途是什么? 目的是防止该引用被用来修改它所引用的对象。

int i = 42; // non const object
const int &r1 = i; // const reference to non const object
r1 = 6 * 9; // error, r1 cannot be used to modify i;

【讨论】:

@Caleth 对,但它最初所说的是它通常会阻止该对象被修改。现在答案已更正,所以我删除了我的评论。 这如何与const string&const vector<...>& 之类的东西一起使用? C++ 中是否有一些魔法阻止您使用这些对象上的方法来修改它们?还是仅仅意味着您不能完全重新分配它们? @ThomasAhle 没有什么神奇之处,如果您尝试编写在const 对象上调用非const 方法的代码,编译器就会发出错误。例如,查看像 这样的包含文件,您会看到一个方法列表,其中一些标记为 const,而另一些则没有。前者保证不修改对象。后者不能在 const 对象上调用,也不能通过 const 引用或指针调用。【参考方案2】:

为了更好地理解它,您可以查看 const 指针和指向 const 数据的指针之间的区别:

int i, j;
const int *p1 = &i; // pointer to constant int
int *const p2 = &i; // constant pointer to int

*p1 = 0; // error, p1 points to const int
*p2 = 0; // it is fine sets i to 0

 p1 = &j; // fine p1 now points to anbother int
 p2 = &j; // error, p2 is a constant pointer

所以现在如果我们替换指向引用的指针,我们可以看到类似的东西,除了引用本身是不可改变的,即你不能在创建后引用另一个对象(不像非常量指针)并且任何引用都像常量指针。所以这个意义上的 const 引用没有任何意义,通常人们所说的 const 引用是指对 const 类型的引用。这就是引述引述的意思。

至于您的代码中的差异,是的,存在差异 - 您不能通过 const 引用更改对象,无论该引用是否指向 const 对象。

【讨论】:

【参考方案3】:

有一个有用的方法可以弄清楚constness 在指针和引用中的含义,即从右到左阅读声明(参见these answers)。所以const int &r1 可以读作“r1 是对int const 的引用”。

基本上,r1 指的是无法修改的int。这意味着引用的intconst int是一个简单的int。将const const 引用绑定到非const 对象(例如,在编写int i = 5; const int& r = i; 之类的内容时)是完全合法的,因为不修改非const 对象没有任何问题。

【讨论】:

"在第二种情况下提升为 const ......" 你的意思是第一种情况(也就是 const 对非 const 对象的引用)? @SteveCho 我指的是我自己的措辞,而不是原始问题。原谅我,我已经澄清了。【参考方案4】:

我认为这意味着当引用非 const 对象时,将引用设为“const”绝对没有任何作用。在定义那个引用时,我们不妨去掉那个 const 关键字。

不正确。

不得通过const 引用修改非const 对象。 您可以通过非const 引用修改非const 对象。

除非在程序的只读部分中创建对象,否则可以对其进行修改而不会产生不良后果。但是,当您使用const 对非const 对象的引用时,您要求编译器不允许您通过该特定引用修改对象。这并不意味着你不会修改对象。

它类似于函数参数。当函数使用const 引用参数类型时,该函数向您承诺它不会修改对象。这并不意味着该对象根本不可修改。

【讨论】:

“当函数使用非常量引用参数类型时,该函数向您承诺它不会修改对象。”您的意思是“当函数使用 CONST 引用时...”?【参考方案5】:

如果我们将 const 与变量一起使用,则它的值不能改变,当它与 const 引用一起使用时,如果我们将它与对象一起使用,则它的引用不能改变,那么整个数据在对象中使用它不能改变。

【讨论】:

【参考方案6】:

还值得一提的是,当您将两者都传递给函数调用时的行为 fun1(const int& R1) 与 fun2(int & R1)

在 fun1 中,您可以使用成本或变量来调用它,例如 fun1(5) 或 fun1(var1);假设 int var1=5;

在 fun2 中,你根本不能用 const 调用它,fun2(5) 会给你编译器错误,这意味着在这种情况下你必须添加另一个重载实现来覆盖这种情况。糟糕的设计!

【讨论】:

以上是关于C++ 常量引用非常量对象和非常量引用非常量对象之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

为啥非常量引用不能绑定到临时对象?

从 const 引用初始化非常量对象时防止复制

C++核心准则边译边学-F.17 输入/输出参数传递非常量引用

“非常量引用的初始值必须为左值“及“匿名对象“

为啥我们可以非常量引用临时对象并延长其生命周期?

非常量左值引用的示例