为什么引用不能捕获临时值,而 const 引用和右值引用可以捕获并延长对象寿命。换句话说,虽然前两行是合法的,但第三行不合法:
const string &a = string("a");
string &&b = string("b");
string &c = string("c"); // why illegal?
为什么引用不能捕获临时值,而 const 引用和右值引用可以捕获并延长对象寿命。换句话说,虽然前两行是合法的,但第三行不合法:
const string &a = string("a");
string &&b = string("b");
string &c = string("c"); // why illegal?
引自N1377
Bjarne 在其出色的文章“C++ 的设计和演变”中讨论了在第 3.7 节中禁止将右值绑定到非 const 引用的动机。显示以下示例:
void incr(int& rr) {rr++;}
void g()
{
double ss = 1;
incr(ss);
}
ss 不会递增,因为必须创建一个临时 int 才能传递给 incr()。作者想说的是,我们 100% 同意这一分析。霍华德甚至被早期编译器的这个“错误”所困扰。他花了很长时间才弄清楚发生了什么(在这种情况下,是从浮点数到双精度数的隐式转换创建了临时)。
这个基本原理(不将右值绑定到非常量(左值)引用)从 C++ 诞生之初就一直存在,直到 C++11(2011 年)。然而,同样的理由不适用于对 const 的左值引用:
将临时值绑定到对 const 的左值引用是“安全的”,因为编译器会告诉您是否不小心对此临时值进行了“无用”修改。
那么为什么将右值绑定到右值引用是“安全的”呢?
再次引用N1377:
话虽如此,我们想补充一点:您永远不想将临时对象绑定到非常量引用......除非您这样做。
非常量引用并不总是旨在成为“out”参数。考虑:
template <class T>
class auto_ptr
{
public:
auto_ptr(auto_ptr& a);
...
};
“复制”构造函数采用名为“a”的非常量引用。但是修改“a”并不是这个函数的主要目标。主要目标是通过窃取“a”来构造一个新的 auto_ptr。如果“a”碰巧引用了一个右值,这不是一个逻辑错误!
总之,有时你想修改一个右值,有时你不想。不同类型的引用允许程序员告诉编译器他们处于哪种情况。
您问题中的绑定是由 N1377 激发的绑定的合乎逻辑的结论。
移动语义提案确实致力于提出一个不需要更改语言的解决方案(即引入右值引用)。然而,仅库的解决方案并不令人满意,因为构建诸如移动构造函数之类的东西的语法过于复杂。