【发布时间】:2014-05-15 17:26:00
【问题描述】:
我们不能写int& ref = 40,因为我们需要在右侧写lvalue。但是我们可以写const int& ref = 40。为什么这可能? 40 是 rvalue 而不是 lvalue
我知道这是个例外,但为什么呢?
【问题讨论】:
我们不能写int& ref = 40,因为我们需要在右侧写lvalue。但是我们可以写const int& ref = 40。为什么这可能? 40 是 rvalue 而不是 lvalue
我知道这是个例外,但为什么呢?
【问题讨论】:
正如 Stroustrup 所说:
const T& 的初始值设定项不必是左值,甚至不必是类型 T. 在这种情况下:
[1] 首先,必要时应用到 T 的隐式类型转换。
[2] 然后,将结果值放在一个临时变量中 键入 T。
[3] 最后,这个临时变量被用作 初始化器。
所以,当你输入const int& ref = 40时,会在后台创建临时int变量,并将ref绑定到这个临时变量。
【讨论】:
语言中有一条规则允许将 const 左值引用绑定到右值。该规则的主要原因是,如果它不存在,那么您必须提供不同的函数重载才能使用临时变量作为参数:
class T; // defined somewhere
T f();
void g(T const &x);
有了这个规则,你可以做g(f()),没有它,你必须创建一个不同的g重载,它需要一个右值(这是从那时甚至没有语言中的右值引用!)
【讨论】:
T const& _ = ...;或T const _ = ...;,两者都可以工作,当表达式产生引用时前者效率更高(没有副本)。这确实很不幸,因为它让很多东西溜进来。
T const& x = f(); 后跟 any odr-use of x 将是未定义的行为,提出了为什么首先允许这样做的问题?因此,您要么提供一致性(any 上下文中的引用绑定)并延长生命周期,要么接受不一致并且不需要延长生命周期。语言是前者。
为什么会这样?
40 在这里是一个文字。常量引用可以用文字和临时变量初始化以延长它们的生命周期。这可以通过编译器来完成:
int const& ans = 40;
// transformed:
int __internal_unique_name = 40;
int const& ans = __internal_unique_name;
另一种情况是当你有一个函数时,例如:
void f( std::string const& s);
你想用它来调用它
f( "something");
这个临时变量只能绑定到 const 引用。
【讨论】:
std::string __tmp("something"); f(__tmp);。那是 因为你可以 不是允许 const 引用(单独)的理由,正如 Solaris CC 和 VS 都支持绑定非-const 通过执行完全相同的操作来引用临时对象。
您可以将右值绑定到 const 引用。该语言保证绑定对象一直存在,直到引用范围结束,甚至静态调用正确的析构函数。这是例如在 ScopeGuard 实现 (http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758?pgno=2) 中使用以具有类似虚拟析构函数的行为,而无需为虚拟方法调用付费。
【讨论】: