当函数参数的类型为lvalue reference lref
时:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
和lref
绑定到prvalue:
PrintAddress(lref.substr() /* temporary of type std::string */)
地址代表什么?那里住着什么?
prvalue无法获取其地址。但是左值引用到一个prvalue 可以得到它的地址,这对我很好奇。
答案 0 :(得分:5)
在函数lref
内部不是prvalue它是左值,你可以获取它的地址。
关于右撇子与左撇子存在一种常见的误解。
命名参数始终是左值。无论它是否是绑定到右值的引用类型。通过const &
引用类型,您甚至无法确定对象在调用函数时实际具有哪种值类别。 Rvalue引用和非const Lvalue引用为您提供了这些信息:
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...
}
临时字符串是调用者上下文中的prvalue(在PrintAddress
处被调用)。在被调用者的上下文中(在PrintAddress
中)lref
是左值引用,因为在此上下文中它实际上是左值。
PrintAddress
并不知道传递参数的有限生命周期以及PrintAddress
&#39;对象是&#34;总是&#34;那里。
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
是一个左值(它有一个名字)所以你可以拿它的地址加上它是可变的。
答案 1 :(得分:4)
简而言之,因为prvalue的寿命已经延长。通过任何参考延长其寿命,它是一个左值,因此可以得到它的地址。
地址代表什么?那里住着什么?
地址代表一个对象,即lref
引用的对象。
prvalue是短暂的,它不会长寿。实际上,当创建它的语句结束时它将被销毁。
但是,当您创建对prvalue(rvalue引用或const lvalue引用)的引用时,它的生命周期会被扩展。 Ref.::
rvalue 可用于初始化 const lvalue [ rvalue ]引用,在这种情况下,对象的生命周期由 rvalue 延长,直到参考范围结束。
现在获取其地址实际上是合理的,因为它是所有意图和目的的左值。现在,prvalue具有不确定的生命周期,它是一个左值。
然而,取一个prvalue的地址是没有意义的,这可能是为什么它被禁止的原因:
如果您获取某些内容的地址,则需要编译器实际创建该对象。有时,编译器会优化掉微不足道的变量,但是如果要获取它们的地址,则不允许编译器优化它们。
获取prvalue的地址将导致编译器无法完全忽略该值,因为没有任何优势(参见第1点)。
答案 2 :(得分:3)
用简单的英语:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
任何具有名称的对象都是lvalue
,因此在上述功能范围内使用lref
是lvalue
使用。
使用以下方法调用函数时
PrintAddress(lref.substr() /* temporary of type std::string */)
原因是,lref.substr()
生成一个临时的rvalue
,但rvalues
可以绑定(使其生命周期延长)const左值引用或右值引用。
即使你提供rvalue
重载,因为它有一个名字,它的&#34;左右的内容&#34; 其范围,例如:
#include <string>
#include <iostream>
void PrintAddress(const std::string& lref) {
std::cout << "LValue: " << &lref << std::endl;
}
void PrintAddress(std::string&& `rref`) {
std::cout << "RValue: " << &rref << std::endl; //You can take address of `rref`
}
int main(){
std::string str = "Hahaha";
PrintAddress(str);
PrintAddress(str.substr(2));
}
请记住:
在C ++中,任何对象(无论是值类型,引用类型或指针类型)都有 name 是左值
也知道some expressions也会产生左值。