对纯右值的左值引用的地址代表什么?
What does the address of an lvalue reference to a prvalue represent?
当函数参数是左值引用类型时lref
:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
和 lref
绑定到纯右值:
PrintAddress(lref.substr() /* temporary of type std::string */)
地址代表什么?那里住着什么?
纯右值的地址不能被占用。但是左值引用 to 纯右值 can 的地址被占用,这让我很好奇。
函数内部 lref
不是纯右值,它是左值,您可以获取它的地址。
对于右值与左值存在一种常见的误解。
命名参数始终是左值。不管它是否是绑定到右值的引用类型。通过 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
被调用时)。在被调用者的上下文中(在 PrintAddress
中),lref
是一个左值引用,因为在这个上下文中它实际上是一个左值。
PrintAddress
不知道传递参数的有限生命周期,从 PrintAddress
的角度来看,对象 "always" 在那里。
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
函数范围的末尾)。
what does the address represent? What lives there?
包含传递内容的 std::string
对象。
And is it legal (in C++, and with respect to memory) to write to that address?
不,如果您使用右值引用是合法的:
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
是一个左值(它有一个名称)所以你可以获取它的地址加上它是可变的。
简单的英语:
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
重载,因为它有一个名称,它是一个 "lvalue of something"在其范围内,例如:
#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));
}
记住:
In C++, any object(whether value type, reference type or pointer type) that has a name is an lvalue
也知道 some expressions 也产生 左值 。
简而言之,因为纯右值的生命周期被延长了。通过延长它的生命周期——通过任何引用——它是一个左值,因此它的地址可以被占用。
what does the address represent? What lives there?
地址代表一个对象,lref
引用的对象。
纯右值是短暂的,它不会长寿。事实上,它会在创建它的语句结束时被销毁。
但是,当您创建对纯右值的引用(右值引用或 const 左值引用)时,它的生命周期会延长。 Ref.::
An rvalue may be used to initialize a const lvalue [rvalue] reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
现在获取它的地址实际上是有意义的,因为它是所有意图和目的的左值。现在,纯右值具有不确定的生命周期,它是一个左值。
获取纯右值的地址没有任何意义,这可能就是它被禁止的原因:
值在下一条语句后被销毁,所以你不能对地址做任何事情,除非打印出来。
如果你取某物的地址,编译器需要实际创建对象。有时,编译器会优化出一些微不足道的变量,但如果你要获取它们的地址,编译器将不允许优化它们。
获取纯右值的地址将导致编译器无法完全省略该值,没有任何好处(请参阅第 1 点)。
当函数参数是左值引用类型时lref
:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
和 lref
绑定到纯右值:
PrintAddress(lref.substr() /* temporary of type std::string */)
地址代表什么?那里住着什么?
纯右值的地址不能被占用。但是左值引用 to 纯右值 can 的地址被占用,这让我很好奇。
函数内部 lref
不是纯右值,它是左值,您可以获取它的地址。
对于右值与左值存在一种常见的误解。
命名参数始终是左值。不管它是否是绑定到右值的引用类型。通过 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
被调用时)。在被调用者的上下文中(在 PrintAddress
中),lref
是一个左值引用,因为在这个上下文中它实际上是一个左值。
PrintAddress
不知道传递参数的有限生命周期,从 PrintAddress
的角度来看,对象 "always" 在那里。
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
函数范围的末尾)。
what does the address represent? What lives there?
包含传递内容的 std::string
对象。
And is it legal (in C++, and with respect to memory) to write to that address?
不,如果您使用右值引用是合法的:
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
是一个左值(它有一个名称)所以你可以获取它的地址加上它是可变的。
简单的英语:
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
重载,因为它有一个名称,它是一个 "lvalue of something"在其范围内,例如:
#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));
}
记住:
In C++, any object(whether value type, reference type or pointer type) that has a name is an lvalue
也知道 some expressions 也产生 左值 。
简而言之,因为纯右值的生命周期被延长了。通过延长它的生命周期——通过任何引用——它是一个左值,因此它的地址可以被占用。
what does the address represent? What lives there?
地址代表一个对象,lref
引用的对象。
纯右值是短暂的,它不会长寿。事实上,它会在创建它的语句结束时被销毁。
但是,当您创建对纯右值的引用(右值引用或 const 左值引用)时,它的生命周期会延长。 Ref.::
An rvalue may be used to initialize a const lvalue [rvalue] reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
现在获取它的地址实际上是有意义的,因为它是所有意图和目的的左值。现在,纯右值具有不确定的生命周期,它是一个左值。
获取纯右值的地址没有任何意义,这可能就是它被禁止的原因:
值在下一条语句后被销毁,所以你不能对地址做任何事情,除非打印出来。
如果你取某物的地址,编译器需要实际创建对象。有时,编译器会优化出一些微不足道的变量,但如果你要获取它们的地址,编译器将不允许优化它们。
获取纯右值的地址将导致编译器无法完全省略该值,没有任何好处(请参阅第 1 点)。