右值引用被视为左值?
我发布了这个答案:https://stackoverflow.com/a/28459180/2642059 其中包含以下代码:
I posted this answer: https://stackoverflow.com/a/28459180/2642059 Which contains the following code:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
bar
是右值还是左值?
我之所以这么问是因为我显然不能获取右值的地址,但我可以像这里所做的那样获取右值引用的地址.
I ask because I obviously cannot take the address of an rvalue, yet I can take the address of an rvalue reference as is done here.
如果您可以对右值引用执行任何可以对左值引用执行的操作,那么使用&&"区分两者的意义何在?而不仅仅是一个&"?
If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the "&&" instead of just an "&"?
推荐答案
bar
是右值还是左值?
问题自己回答.任何有名字的都是左值(1).所以 bar
是一个左值.它的类型是对string
的右值引用",但它是那种类型的左值.
The question answers itself. Whatever has a name is an lvalue(1). So bar
is an lvalue. Its type is "rvalue reference to string
", but it's an lvalue of that type.
如果你想把它当作一个右值,你需要对它应用std::move()
.
If you want to treat it as an rvalue, you need to apply std::move()
to it.
如果您可以对右值引用执行任何可以对左值引用执行的操作,那么使用&&"区分两者的意义何在?而不仅仅是一个&"?
If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the "&&" instead of just an "&"?
这取决于您对执行操作"的定义.左值引用和(命名的)右值引用在如何在表达式中使用它们几乎相同,但它们在可以绑定到它们的内容上很多不同.左值可以绑定到左值引用,右值可以绑定到右值引用(任何东西都可以绑定到 const
的左值引用).也就是说,您不能将右值绑定到左值引用,反之亦然.
This depends on your definition of "perform an operation." An lvalue reference and a (named) rvalue reference are pretty much identical in how you can use them in expressions, but they differ a lot in what can bind to them. Lvalues can bind to lvalue references, rvalues can bind to rvalue references (and anything can bind to an lvalue reference to const
). That is, you cannot bind an rvalue to an lvalue reference, or vice versa.
我们来说说一个右值引用类型的函数参数(比如你的bar
).重要的不是 bar
是什么,而是你对 bar
所指的值的了解.由于 bar
是一个右值引用,你肯定知道任何绑定到它的是一个右值.这意味着当完整的表达式结束时它一定会被销毁,你可以安全地将其视为右值(通过窃取其资源等).
Let's talk about a function parameter of rvalue reference type (such as your bar
). The important point is not what bar
is, but what you know about the value to which bar
refers. Since bar
is an rvalue reference, you know for certain that whatever bound to it was an rvalue. Which means it's bound to be destroyed when the full expression ends, and you can safely treat it as an rvalue (by stealing its resources etc.).
如果您不是直接对 bar
执行此操作的人,而只是想传递 bar
,您有两个选择:要么完成 bar
code>bar,然后你应该告诉下一个收到它的人它绑定到一个右值—do std::move(bar)
.或者你需要用bar
做更多的事情,所以你不希望任何人从你下面窃取它的资源,所以把它当作一个左值—bar
>.
If you're not the one doing this directly to bar
, but just want to pass bar
on, you have two options: either you're done with bar
, and then you should tell the next one who receives it that it's bound to an rvalue—do std::move(bar)
. Or you'll need to do some more things with bar
, and so you do not want anyone inbetween stealing its resources from under you, so just treat it as an lvalue—bar
.
总结一下:区别不在于您拥有引用后可以做什么.区别在于可以绑定到引用的内容.
To summarise it: The difference is not in what you can do with the reference once you have it. The difference is what can bind to the reference.
(1) 一个很好的经验法则,除了少数例外:枚举器有名字,但都是右值.类、命名空间和类模板有名称,但不是值.
(1) A good rule of thumb, with minor exceptions: enumerators have names, but are rvalues. Classes, namespaces and class templates have names, but aren't values.
相关文章