为什么const / nonconst左值引用都绑定到右值引用?

时间:2016-12-01 11:08:55

标签: c++ rvalue-reference rvalue

允许使用这个非常简单的代码:

class s
{
public:
};

const s& tt = std::move(s()); // Also valid without 'const'

但是现在我想知道为什么这是允许的..

首先我们使用std::move并将右值(临时值)标记为右值引用,但为什么左值引用可以绑定到右值引用?

是因为右值参考也是右值?

导致左值引用绑定到右值引用的基本原理(或标准引号)是什么? 可以完成我得到了它

编辑:msvc2015允许非对象左值引用绑定到右值引用,问题仍然是const值左侧引用绑定到右值引用。对不起,我应该指定我使用的编译器。

1 个答案:

答案 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左值引用,除了允许通过引用传递临时参数之外,对于不知道确切参数类型但是你想允许移动语义的情况也很有用。有可能的。假设我正在调用一个可以定义为constfoo2(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超出范围之前不会被销毁。