在函数中使用时,右值引用是否被视为左值?

问题描述 投票:0回答:4

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

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

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

bar
是右值还是左值?

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

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

c++ c++11 rvalue-reference lvalue rvalue
4个回答
70
投票

bar
是右值还是左值?

问题本身就有答案。凡是有名字的都是左值(1)。所以

bar
是左值。它的 type 是“对
string
的右值引用”,但它是该类型的左值。

如果你想将其视为右值,则需要对其应用

std::move()


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

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


我们来谈谈右值引用类型的函数参数(比如你的

bar

)。重要的不是

bar
是什么,而是您对
bar
所指的值了解多少。由于
bar
是一个右值引用,因此您可以肯定地知道,无论绑定到它
 都是右值。
这意味着当完整表达式结束时它必然会被销毁,并且您可以安全地将其视为右值(通过窃取其资源等)。 如果您不是直接对

bar

执行此操作的人,而只是想传递

bar
,您有两种选择:要么完成
bar
,然后您应该告诉下一位谁接收到它绑定到右值 — 执行
std::move(bar)
。或者你需要用
bar
做更多的事情,所以你不希望任何人从你下面窃取它的资源,所以只需将它视为左值 -
bar

总结一下:

区别不在于您拥有引用后

可以对它做什么。区别在于可以绑定到引用。


(1)

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


13
投票
bar 是
右值

还是左值

它是一个
左值

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

如果您可以对
rvalue

引用执行任何可以在 lvalue 引用上执行的操作,那么用“&&”而不是仅用“&”来区分两者有何意义?

您只能使用
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



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

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

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


-2
投票

命名右值引用是左值,而如果输入类型是常量命名右值引用,那么它将是右值 #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; }

© www.soinside.com 2019 - 2024. All rights reserved.