函数内部lref
不是纯右值,而是左值,您可以获取它的地址。
关于右值与左值有一个常见的误解。命名参数始终是左值。不管它是否是绑定到右值的引用类型。通过const &
引用类型,您甚至无法判断对象在调用函数时实际具有哪种类型的值类别。右值引用和非 const 左值引用为您提供以下信息:
void foo(std::string& L, std::string&& R)
{
// yeah i know L is already an lvalue at the point where foo is called
// R on the other hand is an rvalue at the point where we get called
// so we can 'safely' move from it or something...
}
临时字符串是调用者上下文中的纯右值(此时PrintAddress
被调用)。在被调用者的上下文中 (in PrintAddress
)lref
是一个左值引用,因为在这个上下文中它实际上是一个左值。
PrintAddress
不知道传递参数的有限生命周期,从PrintAddress
' 的角度来看,对象“总是”在那里。
std::string q("abcd");
PrintAddress(q.substr(1)); // print address of temporary
在概念上等同于:
std::string q("abcd");
{
const std::string& lref = q.substr(1);
std::cout << &lref << std::endl;
}
其中临时对象的生命周期延长到lref
定义的范围的末尾(PrintAddress
在本示例中为函数范围的末尾)。
地址代表什么?那里住着什么?
std::string
包含传递内容的对象。
写入该地址是否合法(在 C++ 中,以及关于内存)?
不,如果您使用右值引用,那将是合法的:
void PrintAddressR(std::string&& rref) {
rref += "Hello"; // writing possible
std::cout << &rref << std::endl; // taking the address possible
}
// ...
PrintAddressR(q.substr(1)); // yep, can do that...
这同样适用于这里:rref
是一个左值(它有一个名字),所以你可以把它的地址加上它是可变的。