非 const 引用只能绑定到左值。

18

请问有人能够解释如何模拟这个错误?同时,这个错误信息在说什么问题?

"在C++中,非常量引用只能绑定到左值"。


(说明:左值指的是表达式结束后依然存在的持久对象,例如变量或者函数返回值。右值则是表达式结束后临时产生的值,例如字面量或者函数返回的匿名对象。)

2
你不理解哪些术语,“非常量引用”、“绑定”还是“左值”? - john
1
@Seth:这个问题是在寻求一些能够产生这种错误的代码。提问者无法满足你的要求。 - Steve Jessop
@Steve 是的,我的眼睛漏掉了“模拟”这个词。 - Seth Carnegie
2个回答

53

lvalue 大致上可以理解为在赋值语句的左侧可能出现的任何内容。而引用则提供了其他对象的别名:

std::string s;
std::string & rs = s;  // a non-const reference to s
std::string const & crs = s; // a const reference to s

根据上述定义,引用 rscrs 与引用 s 相同,只是通过 crs 您不能修改所引用的字符串,因为它是常量。变量是左值,因此您可以将非常量引用绑定到它。相反,您可以像这样将常量引用绑定到临时值:

std::string const & crs1 = std::string();

然而,以下操作是非法的:

std::string & rs1 = std::string();

这是因为使用非const引用意味着您想要修改所引用的对象。然而,绑定到引用的临时对象在引用超出作用域时被销毁。由于C ++创建临时对象的时间不总是直观的,将它们绑定到非const引用已被禁止,以避免让您惊 unpleasant地发现您喜欢的对象已更改,仅仅是为了在几个语句之后看到它被销毁。


@Nicola,这里有一个问题。 int method1(int & a); 现在,这个也适用于这个吗? - Pavan Dittakavi
当然。一个直接的后果是你不能将整数字面量作为参数调用这个函数。 - Nicola Musatti
1
@Nicola:实际上,我一直觉得这个限制相当武断。例如,你可以在临时对象上调用非const方法,或者const方法实际上可能会修改可变属性,这与之不符。 - Matthieu M.
@Matthieu M.:嗯,如果可以将临时变量绑定到非const引用,我可以看到自己偶尔会被愚弄,但是你是对的,这种情况是不一致的。显然,因此一些标准化委员会成员希望禁止在临时变量上调用非const成员函数。 - Nicola Musatti
1
@Matthieu:虽然不是完全一致,但考虑到隐式转换应用于函数参数而不是成员函数调用的LHS,我认为这是有意义的。因此,如果可以绑定非const引用,则void increment(long &i) { ++i; }会毁掉你的一天,如果你不小心将一个int变量的名称作为参数传递,则会指出并嘲笑你。但是,如果类型X转换为类型Y,并且类型Y具有非const成员函数“increment”,则没有等效的危险,您编写X x; x.increment();然后想知道为什么x未更改。 - Steve Jessop
因此,允许在临时对象上调用成员函数是“安全”的,但是将临时对象作为非const引用参数是“不安全”的。也就是说,首先判断传递转换结果的引用是否是所需的,以及是否值得语言禁止它,而代价是禁止某些有意义的事情:std::ofstream("filename") << "hello\n"是允许的,但是 std::ofstream("filename") << Foo();则不是,因为相关的operator<<必须是非成员的。 - Steve Jessop

10
这意味着你不能像这样做:
void foo(int &x) { ... }
int bar()        { ... }

foo(bar());

您需要让函数foo接受一个const引用,或者将bar()的结果赋值给一个变量,然后将该变量传递给foo函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接