rvalue引用和lvalue引用作为函数参数的区别

10
阅读完这篇文章:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html,我还是无法理解当你编写函数时,需要以左值或右值引用作为参数的情况,例如这样:
void printReference (const string& str)
{
    cout << str;
}

void printReference (string&& str)
{
    cout << str;
}

为什么第一个printReference函数可以接受任何参数,无论是左值还是右值,以及左值或右值是否可变。然而,在第二个printReference函数中,只允许传递可变的右值。

也许我的理解有误,有人可以帮我弄清楚吗。


为什么?因为语言规范是这样规定的。你是在问这个规定的原因吗?虽然我认为你对于“可变右值”是错误的。它不一定是可变的(它可以是一个字面常量)。 - juanchopanza
@juanchopanza 是的,我和你一样困惑。帖子中的原句是 然而,在第二个重载函数 printReference 接受一个右值引用参数的情况下,它将接收除可变右值引用之外的所有值。 你知道它的意思吗? - sydridgm
那篇文章看起来有点过时。lvalue和rvalue这些术语来自C++03(以及更早的版本)。自从C++11之后,我们添加了几个更多的值类别(gl/x/pr),你应该对它们有一个基本的理解。 - Martin York
2个回答

14
第一个选项可以接受左值因为它是一个左值引用。它可以接受右值,因为它被标记为const,而右值可以绑定到const的左值引用。
第二个版本只允许非const的右值,因为你不能隐式地从引用中删除const,而右值引用不允许左值绑定到它们。
语义上的区别在于前一个函数表示“我只是要读取你传递给我的内容,而且我不想复制它”,而后一个函数表示“我保留了将此对象解体并用它们来涂漆我的客厅的权利”。

2
哈哈哈哈,有趣的比喻!它帮助我在生活中牢记。 - sydridgm

7

只有常量左值引用可以绑定到临时对象。

所以这个函数

void printReference (const string& str)
{
    cout << str;
}

可能需要以下对象:
const std::string s1( "constant lvalue" );
printReference( s1 );

std::string s2( "non-constant lvalue" );
printReference( s2 );

printReference( "A temporary object of type std::string" );

printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );

关于这个功能
void printReference (string&& str)
{
    cout << str;
}

在上述对象中,您只能为非常量rvalue调用它。
printReference( "A temporary object of type std::string" );

您可能不会像这样调用它

printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );

由于存在const限定符,因此会导致如下问题。

如果您以以下方式重载函数

void printReference (const string&& str)
                     ^^^^^
{
    cout << str;
}

那么这个调用
printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );
                 

将会是有效的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接