我发布了这个答案:https://stackoverflow.com/a/28459180/2642059其中包含以下代码:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
bar
是右值还是左值?
我问这个问题是因为我显然不能获取右值的地址,但我可以获取右值引用的地址,就像这里所做的那样。
如果您可以对右值引用执行任何可以对左值引用执行的操作,那么用“&&”而不是仅用“&”来区分两者有何意义?
是右值还是左值?bar
问题本身就有答案。凡是有名字的都是左值(1)。所以
bar
是左值。它的 type 是“对 string
的右值引用”,但它是该类型的左值。
如果你想将其视为右值,则需要对其应用
std::move()
。
如果您可以对右值引用执行任何可以对左值引用执行的操作,那么用“&&”而不是仅用“&”来区分两者有何意义?
这取决于您对“执行操作”的定义。左值引用和(命名)右值引用在表达式中使用它们的方式几乎相同,但它们在可以绑定到它们的内容方面有很大不同。左值可以绑定到左值引用,右值可以绑定到右值引用(任何内容都可以绑定到 const
的左值引用)。也就是说,您不能将右值绑定到左值引用,反之亦然。
我们来谈谈右值引用类型的函数参数(比如你的
bar
)。重要的不是
bar
是什么,而是您对 bar
所指的值了解多少。由于 bar
是一个右值引用,因此您可以肯定地知道,无论绑定到它 都是右值。这意味着当完整表达式结束时它必然会被销毁,并且您可以安全地将其视为右值(通过窃取其资源等)。 如果您不是直接对
bar
执行此操作的人,而只是想传递
bar
,您有两种选择:要么完成 bar
,然后您应该告诉下一位谁接收到它绑定到右值 — 执行 std::move(bar)
。或者你需要用 bar
做更多的事情,所以你不希望任何人从你下面窃取它的资源,所以只需将它视为左值 - bar
。总结一下:区别不在于您拥有引用后
可以对它做什么。区别在于可以绑定到引用。
一个很好的经验法则,除了一些小的例外:枚举数有名称,但是是右值。类、命名空间和类模板有名称,但不是值。
右值左值还是左值?
它是一个
,就像任何命名变量的表达式一样。
如果您可以对rvaluervalue引用执行任何可以在 lvalue 引用上执行的操作,那么用“&&”而不是仅用“&”来区分两者有何意义?
您只能使用
表达式初始化 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
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;
}