我发布了这个答案:https://stackoverflow.com/a/28459180/2642059其中包含以下代码:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
字符串bar
是左值还是右值?
我之所以问这个问题,是因为我显然不能取右值的地址,但我可以像这里一样取右值引用的地址。
如果你可以在右值引用上执行任何你可以在左值引用上执行的操作,那么用“&&”而不仅仅是“&"来区分两者有什么意义呢?
4条答案
按热度按时间kyks70gy1#
bar
是左值还是右值?这个问题本身就有答案了。任何有名字的东西都是一个左值(1)。所以
bar
是一个左值。它的 type 是“对string
的右值引用“,但它是那种类型的左值。如果要将其视为右值,则需要对它应用
std::move()
。如果你可以在右值引用上执行任何你可以在左值引用上执行的操作,那么用“&&”而不仅仅是“&"来区分两者有什么意义呢?
这取决于你对“执行操作”的定义。左值引用和(命名的)右值引用在你如何在表达式中使用它们方面几乎是一样的,但是它们在绑定到它们的对象方面有很大的不同。左值可以绑定到左值引用,右值可以绑定到右值引用(任何东西都可以绑定到
const
的左值引用),也就是说,你不能将右值绑定到左值引用,反之亦然。让我们来讨论一个右值引用类型的函数参数(例如
bar
)。重点不是bar
是什么,而是您对bar
引用的值了解多少。由于bar
是一个右值引用,因此您可以确定绑定到它的任何内容 * 都是一个右值。* 这意味着当完整表达式结束时,它必然会被销毁。您可以安全地将其视为右值(通过窃取其资源等)。如果您不是直接向
bar
执行此操作的人,而只是想将bar
传递给它,则有两种选择:要么你已经处理完了bar
,然后你应该告诉下一个接收它的人它绑定到了一个右值-dostd::move(bar)
,要么你需要对bar
做更多的事情,所以你不想让任何人从你下面窃取它的资源,所以就把它当作一个左值-bar
。总结一下:区别不在于拥有引用 * 后您可以对其执行哪些操作。 区别在于可以将哪些内容 * 绑定到 * 引用。*
(1)这是一个很好的经验法则,但有一些小的例外:枚举数有名称,但是右值;类、命名空间和类模板有名称,但不是值。
yv5phkfx2#
bar是右值还是左值?
它是一个左值,就像任何命名变量的表达式一样。
如果你可以在一个 * 右值 * 引用上执行任何操作,你可以在一个 * 左值 * 引用上执行任何操作,那么用“&&”而不仅仅是“&”来区分两者有什么意义呢?
你只能用一个 * rvalue* 表达式初始化一个 * rvalue* 引用。所以你可以传递一个临时字符串给你的函数,但是你不能传递一个字符串变量而不显式地从它移动。这意味着你的函数可以假设参数不再需要,并且可以从它移动。
字符串
gz5pxeao3#
表达式
bar
是一个左值。但它不是“对字符串的右值引用”。表达式bar
是一个左值引用。你可以通过在foo()中添加以下行来验证它:字符串
但我同意Angew的其他解释。
一个右值引用,在它被绑定到一个右值之后,是一个左值引用。实际上它不仅仅是函数参数:
型
如果你可以在右值引用上执行任何你可以在左值引用上执行的操作,那么用“&&”而不仅仅是“&"来区分两者有什么意义呢?
右值引用允许我们在右值过期之前做一些“左值操作”。
gt0wga4j4#
在这种情况下,* 命名右值引用是左值 *,而如果输入类型是 const命名右值引用 ,则它将是 * 右值。
字符串