允许使用这个非常简单的代码:
class s
{
public:
};
const s& tt = std::move(s()); // Also valid without 'const'
但是现在我想知道为什么这是允许的..
首先我们使用std::move
并将右值(临时值)标记为右值引用,但为什么左值引用可以绑定到右值引用?
是因为右值参考也是右值?
导致左值引用绑定到右值引用的基本原理(或标准引号)是什么? 可以完成我得到了它
编辑:msvc2015允许非对象左值引用绑定到右值引用,问题仍然是const值左侧引用绑定到右值引用。对不起,我应该指定我使用的编译器。
答案 0 :(得分:4)
Rvalue引用被隐式转换为rvalues(更具体地说,转换为xvalues)作为标准转换之一(C ++标准的第4章):
任何隐式转换的效果与执行相同 相应的声明和初始化然后使用 作为转换结果的临时变量。 结果是 左值,如果T是左值引用类型或右值引用 函数类型(8.3.2),如果T是对象的右值引用,则为xvalue 输入,然后输入prvalue
Rvalues(包括xvalues)可以绑定到const
左值引用,以便您可以使用这样的参数将临时值传递给函数:
void foo(const bar &a);
// ...
foo(bar());
(临时是一个右值;在这种情况下,bar()
的结果是右值)。没有理由不允许这样做,因为临时总是和包含表达式一样长 - 在本例中是函数调用 - 因此它不会在{{1}内创建悬空引用}。
这意味着始终可以将函数foo
的签名调整为fun(bar)
- 并相应地更改实现! - 因为临时参数仍然被接受,并且从调用者的角度来看语义应该是相同的; fun(const bar &)
表示不会修改对象,如果它是通过副本传递的话也是如此。
不允许非const
引用;一个实际的原因是因为它们暗示应该以某种有意义的方式修改价值,如果价值是暂时的,那么这将失去。但是,如果你真的想这样做,你可以将右值转换为左值,但有一些注意事项,如this answer中对另一个问题的描述。
允许rvalue绑定到const
左值引用,除了允许通过引用传递临时参数之外,对于不知道确切参数类型但是你想允许移动语义的情况也很有用。有可能的。假设我正在调用一个可以定义为const
或foo2(const bar &)
的函数,并且在前一种情况下可能有或没有重载foo2(bar)
,我想允许移动语义尽可能使用(假设foo2(bar &&)
重载将在其实现中使用移动语义);我可以安全地使用foo2(bar &&)
创建一个右值,因为它适用于任何一种情况。这个例子可能看起来有点人为,但在编写模板时可能会出现相当多的问题。在代码中:
std::move
在涉及临时的其他rvalue-to -valval-reference赋值的情况下,临时的生命周期被扩展为引用的生命周期,因此即使在参数传递以外的上下文中也不会创建悬空引用:
bar bb = bar();
foo2(std::move(bb));
// above is legal if foo2 is declared as either:
// foo2(bar)
// foo2(const bar &)
// and in latter case calls overload foo2(bar &&) if it is defined.
在上文中,const bar &b = bar(); // temporary lifetime is extended
对象在参考bar
超出范围之前不会被销毁。