右值参考被视为左值?

时间:2015-02-12 16:54:45

标签: c++ c++11 rvalue-reference lvalue rvalue

我发布了这个答案:https://stackoverflow.com/a/28459180/2642059其中包含以下代码:

void foo(string&& bar){
    string* temp = &bar;

    cout << *temp << " @:" << temp << endl;
}

bar是左值还是右值?

我问,因为我显然不能取rvalue的地址,但我可以像这里所做的那样获取右值引用的地址。

如果你可以对左值参考执行任何操作,你可以在左值参考上用&#34;&amp;&amp;&#34;来区分两者。而不仅仅是&#34;&amp;&#34;?

4 个答案:

答案 0 :(得分:36)

  

bar是左值还是右值?

问题回答了自己。任何名称都是左值(1)。所以bar是一个左值。它的类型是&#34;对string&#34;的右值引用,但它是该类型的左值。

如果您想将其视为左值,则需要对其应用std::move()


  

如果你可以对左值参考执行任何操作,你可以在左值参考上用&#34;&amp;&amp;&#34;来区分两者。而不仅仅是&#34;&amp;&#34;?

这取决于您对&#34;执行操作的定义。&#34;左值引用和(命名)右值引用在表达式中如何使用它们几乎完全相同,但它们在可以绑定到它们的内容上有很多很多。左值可以绑定到左值引用,右值可以绑定到右值引用(任何东西都可以绑定到const的左值引用)。也就是说,您不能将右值绑定到左值引用,反之亦然。

让我们来谈谈右值参考类型的函数参数(例如你的bar)。重要的不是bar是什么,而是您对bar所指的价值的了解。由于bar是一个右值引用,因此您肯定知道绑定到它的任何内容是一个右值。这意味着当完整表达式结束时它必然会被销毁,而你可以安全地将其视为右值(通过窃取其资源等)。

如果您不是直接向bar执行此操作的人,但只是想通过bar,则您有两种选择:要么完成{{1}然后你应该告诉下一个接收它的人,它被绑定到右值 - bar。或者您需要使用std::move(bar)执行更多操作,因此您不希望任何人在中间窃取其资源,因此请将其视为左值 - bar

总结一下:不同之处在于,只要你拥有它就可以使用引用区别在于可以绑定到引用


(1)一个好的经验法则,除了少数例外:枚举器有名称,但是rvalues。类,名称空间和类模板都有名称,但不是值。

答案 1 :(得分:8)

  

bar是 rvalue 还是左值

它是左值,就像命名变量的任何表达式一样。

  

如果您可以对右值参考执行任何操作,您可以在左值参考上使用&#34;&amp;来区分两者之间的区别;&安培;&#34;而不仅仅是&#34;&amp;&#34;?

您只能使用 rvalue 表达式初始化 rvalue 引用。因此,您可以将临时字符串传递给您的函数,但是您无法在不明确移动字符串变量的情况下传递字符串变量。这意味着你的函数可以假设不再需要参数,并且可以从中移动。

std::string variable;
foo(variable);            // ERROR, can't pass an lvalue
foo(std::move(variable)); // OK, can explicitly move
foo("Hello");             // OK, can move from a temporary

答案 2 :(得分:0)

在这种情况下, 名为rvalue引用是lvalues ,而如果输入类型是 const名为rvalue references 那么它将是 rvalue ,这是一个简单的例子:

#include <string>
#include <iostream>

void foo(const std::string&& bar) { 
    std::string* temp = &bar; // compile error, can't get address
    std::cout << *temp << " @:" << temp << std::endl;
}

int main()
{
    foo("test");
    return 0;
}

希望这很有用。

答案 3 :(得分:0)

表达式bar是一个左值。但这不是“对字符串的右值引用”。表达式bar是左值引用。您可以通过在foo()中添加以下行来验证它:

cout << is_lvalue_reference<decltype((bar))>::value << endl; // prints "1" 

但是我同意对Angew的其余解释。

右值引用绑定到右值后,就是左值引用。实际上,不仅仅针对函数参数:

string&& a = "some string";
string&& b = a; // ERROR: it does not compile because a is not an rvalue
  

如果您可以在右值引用上执行任何操作,而可以在左值引用上执行任何操作,那么用“ &&”(而不仅仅是“&”)区分两者的意义何在?

右值引用允许我们在右值到期之前执行一些“左值操作”。