简体   繁体   English

左值引用prvalue的地址代表什么?

[英]What does the address of an lvalue reference to a prvalue represent?

When a function parameter is of type lvalue reference lref : 当函数参数的类型为lvalue reference lref

void PrintAddress(const std::string& lref) {
  std::cout << &lref << std::endl;
}

and lref is bound to a prvalue: lref绑定到prvalue:

PrintAddress(lref.substr() /* temporary of type std::string */)

what does the address represent? 地址代表什么? What lives there? 那里住着什么?

A prvalue cannot have its address taken. prvalue无法获取其地址。 But an lvalue reference to a prvalue can have its address taken, which is curious to me. 但是 prvalue的左值引用可以得到它的地址,这对我很好奇。

Inside the function lref is not a prvalue it is an lvalue and you can take the address of it. 在函数内部, lref不是prvalue,它是一个左值,你可以获取它的地址。

There is a common misconception about rvalues vs. lvalues. 关于右撇子与左撇子有一个共同的误解。 A named parameter is always an lvalue. 命名参数始终是左值。 No matter whether it is a reference type that is bound to an rvalue. 无论它是否是绑定到右值的引用类型。 Through a const & reference type you can't even tell which kind of value category the object actually has at the point where the function is called. 通过const &引用类型,您甚至无法分辨对象在调用函数时实际具有哪种值类别。 Rvalue references and non-const Lvalue references give you that information: 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...
}

The temporary string is a prvalue in the context of the caller (at the point PrintAddress is called). 临时字符串是调用者上下文中的prvalue(在调用PrintAddress )。 Within the context of the callee (in PrintAddress ) lref is an lvalue reference because in this context it actually is an lvalue. 在被调用者的上下文中(在PrintAddress ), lref是左值引用,因为在此上下文中它实际上是左值。

PrintAddress isn't aware of the limited lifetime of the passed argument and from PrintAddress ' point of view the object is "always" there. PrintAddress不知道传递参数的有限生命周期,并且从PrintAddress的角度来看,对象“始终”存在。

std::string q("abcd");
PrintAddress(q.substr(1)); // print address of temporary

is conceptually equivalent to: 在概念上等同于:

std::string q("abcd");
{
    const std::string& lref = q.substr(1);
    std::cout << &lref << std::endl;
}

where the temporary experiences a prolongation of its lifetime to the end of the scope in which lref is defined (which is to the end of PrintAddress function scope in the present example). 其中所述临时经历其寿命,其中所述范围的端部的延长lref被定义(其是在2002年底PrintAddress功能范围在本例中)。


what does the address represent? 地址代表什么? What lives there? 那里住着什么?

A std::string object containing the passed content. 包含传递内容的std::string对象。

And is it legal (in C++, and with respect to memory) to write to that address? 写入该地址是合法的(在C ++中,在内存方面)?

No, it would be legal if you'd use an rvalue reference: 不,如果您使用右值参考,那将是合法的:

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...

The same applies here: rref is an lvalue (it has a name) so you can take its address plus it is mutable. 这同样适用于: rref是一个左值(它有一个名字)所以你可以拿它的地址加上它是可变的。

In short, because the prvalue's lifetime has been extended. 简而言之,因为prvalue的寿命已经延长。 By having its lifetime extended - by any reference -, it's an lvalue, and thus can have its address taken. 通过延长寿命 - 通过任何引用 - 它是一个左值,因此可以得到它的地址。


what does the address represent? 地址代表什么? What lives there? 那里住着什么?

The address represents an object, the object referenced by lref . 地址表示一个对象,即lref引用的对象。

A prvalue is short lived, it doesn't live for long. prvalue是短暂的,它不会长寿。 In fact, it will be destroyed when the statement creating it ends. 实际上,当创建它的语句结束时,它将被销毁。

But, when you create a reference to a prvalue (either an rvalue reference or a const lvalue reference), its lifetime is extended. 但是,当您创建对prvalue(rvalue引用或const lvalue引用)的引用时,它的生命周期会延长。 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 . rvalue可用于初始化const lvalue [ rvalue ]引用,在这种情况下,由rvalue标识的对象的生命周期将延长,直到引用的范围结束

Now it makes actually sense to take its address, as it is an lvalue for all intents and purposes. 现在获取其地址实际上是合理的,因为它是所有意图和目的的左值。 Now, that the prvalue has an indeterminate lifetime, it is an lvalue. 现在,prvalue具有不确定的生命周期,它是一个左值。

Taking the address of a prvalue doesn't make sense however, and that's probably why it is disallowed: 然而,取一个prvalue的地址是没有意义的,这可能是它被禁止的原因:

  • The value is destroyed after the next statements, so you can't do anything with the address, except maybe print it out. 在下一个语句之后,该值将被销毁,因此您无法对该地址执行任何操作,除非将其打印出来。
  • If you take the address of something, the compiler is required to actually create the object. 如果你取一些东西的地址,编译器需要实际创建对象。 Sometimes, the compiler will optimize out variables that are trivial, but if you were to take the address of them, the compiler won't be allowed to optimize them out. 有时,编译器会优化掉微不足道的变量,但是如果要获取它们的地址,则不允许编译器优化它们。

    Taking the address of a prvalue will thus result in the compiler being unable to elide the value completely, for no advantages whatsoever (see point 1). 因此,获取prvalue的地址将导致编译器无法完全忽略该值,因为没有任何优点(参见第1点)。

In simple English: 用简单的英语:

void PrintAddress(const std::string& lref) {
  std::cout << &lref << std::endl;
}

Any object that has a name is an lvalue , hence any use of lref within the scope of the funtion above is an lvalue use. 任何具有名称的对象都是lvalue ,因此在上述功能范围内使用lreflvalue使用。

When you called the function with: 用以下方法调用函数时:

PrintAddress(lref.substr() /* temporary of type std::string */)

Of cause, lref.substr() produces a temporary which is an rvalue , but rvalues can bind to (have its lifetime extended by) const lvalue references or rvalue references. 原因是, lref.substr()生成一个临时rvalue ,它是一个rvalue ,但是rvalues可以绑定(使其生命周期延长)const lvalue引用或rvalue引用。


Even if you provided an rvalue overload, for the fact it has a name , its an "lvalue of something" within its scope, example: 即使你提供了一个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));
}

Just remember: 只记得:

In C++, any object(whether value type , reference type or pointer type ) that has a name is an lvalue 在C ++中, 任何物体(是否值类型引用类型指针类型 ),其具有一个名字是一个左值

Also know that some expressions produce lvalues too. 也知道一些表达式也产生左值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM