左值参考的右值参考与左值/右值的右值引用

rvalue refrence of lvalue reference vs rvalue reference of lvalue/rvalue

本文关键字:值参 参考 引用      更新时间:2023-10-16

对左值引用进行右值引用合法吗?

考虑下面的例子,在最后的rvalureRef中,这两种情况在指代或类型(或其他事物)方面有区别吗?

Type& ref = GetReference()
Type&& rvalueRef = std::move(ref)
vs
Type value = GetValue()
Type&& rvalueRef = std::move(value)

这两个代码在C++中都是正确且100%合法的。区别仅在于,在第一种情况下,引用被移动(或者更好地说,如果使用了适当的目的地,则能够被移动),而在第二种情况中,它是副本(请参阅下面的示例对此进行说明)

请注意,std::move实际上并没有移动对象。它只将对象强制转换为右值引用类型仅此而已。

还要注意的是,在两种情况下,rvalueRef仍然是一个左值—具有名称(即要引用的标识符)的对象永远不是右值。因此,如果您没有再次使用std::move(或使用显式强制转换)来移动它,那么就没有任何区别。

下面是一个具体的例子:

//given function
std::string& GetReference(); 
std::string  GetValue(); 
//target function
void f(std::string param); 

您的代码如下:

std::string& ref = GetReference();
std::string&& rvalueRef = std::move(ref);
std::string value = GetValue()
std::string&& rvalueCopy = std::move(value); //named changed

到目前为止,没有任何差异。

但如果你这样做:

f(std::move(rvalueRef));  //actual object returned from GetReference is moved!
f(std::move(rvalueCopy)); //only a copy is moved.

在第一种情况下移动实际对象,在第二种情况下,移动副本。如果你这样做,根本没有什么区别:

f(std::move(GetReference()));  //actual object returned from GetReference is moved!
f(std::move(GetValue()));      //only a copy is moved.

因此,您可以看到,在您的代码中,没有任何区别,因为根本没有实际的移动。只有演员阵容。要进行实际的移动,应该有一个合适的目标类型,可以调用移动构造函数或移动赋值!在您的情况下,两者都没有调用。

Q 对左值引用进行右值引用合法吗

这不是你真正要问的问题。你真正要问的问题是:

Q 将左值引用强制转换为右值引用合法吗

答案是肯定的。std::move只是将它的自变量强制转换为一个右值引用,它总是合法的。所做操作的总体正确性取决于您对std::move结果所做的操作。您的示例代码没有任何错误。

Q 这两种情况有区别吗

// case 1                             // case 2
Type& ref = GetReference();           Type value = GetValue();
f(std::move(ref));                    f(std::move(value));

唯一的区别是,在情况1中,ref是对GetReference()返回的对象的引用,但在情况2中,valueGetValue()返回对象的副本。