Rvalue参考被视为Lvalue

Rvalue Reference is Treated as an Lvalue?

本文关键字:Lvalue 参考 Rvalue      更新时间:2023-10-16

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

void foo(string&& bar){
    string* temp = &bar;
    cout << *temp << " @:" << temp << endl;
}

bar是右值还是左值?

我之所以这么问,是因为我显然不能接受右值的地址,但我可以接受右值引用的地址,就像这里所做的那样。

如果你可以对右值引用执行任何操作,也可以对左值引用执行操作,那么用"&&"而不仅仅是"&"来区分两者有什么意义?

bar是右值还是左值?

这个问题本身就有答案。任何有名字的都是一个左值(1)。所以bar是一个左值。它的类型是"对string的右值引用",但它是该类型的左值。

如果你想把它当作一个右值,你需要对它应用std::move()


如果你可以对右值引用执行任何操作,也可以对左值引用执行操作,那么用"&&"而不仅仅是"&"来区分两者有什么意义?

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

让我们讨论一下右值引用类型的函数参数(例如bar)。重要的不是bar是什么,而是你对bar所指的值的了解。由于bar是一个右值引用,您可以肯定地知道,与它绑定的任何都是右值这意味着当完整表达式结束时,它一定会被破坏,并且你可以安全地将其视为右值(通过窃取其资源等)。

如果你不是直接对bar这样做的人,而是只想传递bar,你有两种选择:要么你已经完成了bar,然后你应该告诉下一个收到它的人它绑定到一个右值—执行CCD_ 14。或者,你需要用bar做更多的事情,所以你不希望任何人在你身下偷走它的资源,所以把它当作一个左值;CCD_ 16。

总结一下:区别不在于一旦你有了参考,你可以对它做什么。区别在于可以与参考绑定什么


(1)一个很好的经验法则,除了一些小的例外:枚举器有名称,但却是右值。类、命名空间和类模板有名称,但不是值。

bar是右值还是左值

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

如果您可以对右值引用执行任何操作,也可以对左值

只能使用右值表达式初始化右值

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

表达式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

如果你可以对右值引用执行任何操作,也可以对左值引用执行操作,那么用"&&"而不仅仅是"&"来区分两者有什么意义?

右值引用允许我们在右值过期之前进行一些"左值运算"。

在这种情况下,命名右值引用是左值,而如果输入类型是常量命名右值参考,那么它将是右值,这里有一个简单的例子:

#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;
}

希望这是有用的。