首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >lvalue引用prvalue的地址代表什么?

lvalue引用prvalue的地址代表什么?
EN

Stack Overflow用户
提问于 2017-03-12 20:05:24
回答 3查看 731关注 0票数 6

当函数参数类型为lvalue引用lref

代码语言:javascript
复制
void PrintAddress(const std::string& lref) {
  std::cout << &lref << std::endl;
}

lref被绑定到一个prvalue:

代码语言:javascript
复制
PrintAddress(lref.substr() /* temporary of type std::string */)

地址代表什么?那里住的是什么?

不能取它的地址。但是,对prvalue的lvalue引用可以获取它的地址,这对我来说很奇怪。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-03-12 20:23:49

简而言之,因为prvalue的生存期已经延长了。通过延长它的生存期-通过任何引用-,它是一个lvalue,因此它的地址可以被取走。

地址代表什么?那里住的是什么?

该地址表示一个对象,即lref引用的对象。

价值是短暂的,它活不了多久。事实上,当创建它的语句结束时,它将被销毁。

但是,当您创建对prvalue ( rvalue引用或const值引用)的引用时,它的生存期将被延长。参考文献:

rvalue可用于初始化const rvalue引用,在这种情况下,由rvalue标识的对象的生存期被延长,直到引用的范围结束为止。

现在,获取它的地址实际上是有意义的,因为它对于所有意图和目的都是一个值。现在,prvalue具有不确定的生存期,因此它是一个lvalue。

然而,获取prvalue的地址是没有意义的,这可能就是不允许使用prvalue的原因:

  • 值在下一个语句之后被销毁,所以您不能对地址做任何事情,除非可能打印出来。
  • 如果使用某个对象的地址,则需要编译器实际创建该对象。有时,编译器会优化那些琐碎的变量,但是如果您要获取它们的地址,编译器将不被允许对它们进行优化。 因此,获取prvalue的地址将导致编译器无法完全删除该值,而没有任何好处(见第1点)。
票数 4
EN

Stack Overflow用户

发布于 2017-03-12 20:11:58

在函数内部,lref不是prvalue,而是lvalue,您可以获取它的地址。

对于rvalue和lvalue,有一种常见的误解。命名参数始终是一个lvalue。不管它是否是绑定到rvalue的引用类型。通过const &引用类型,您甚至无法判断对象在调用函数时实际拥有哪种类型的值类别。Rvalue引用和非const Lvalue引用为您提供了以下信息:

代码语言:javascript
复制
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是一个lvalue引用,因为在这个上下文中,它实际上是一个lvalue。

PrintAddress不知道传递的参数的生存期有限,从PrintAddress的角度来看,对象是“始终存在”的。

代码语言:javascript
复制
std::string q("abcd");
PrintAddress(q.substr(1)); // print address of temporary

在概念上相当于:

代码语言:javascript
复制
std::string q("abcd");
{
    const std::string& lref = q.substr(1);
    std::cout << &lref << std::endl;
}

其中,临时的生命周期延长到定义lref的作用域的末尾(在本例中,这是PrintAddress函数作用域的结束)。

地址代表什么?那里住的是什么?

包含传递内容的std::string对象。

写到这个地址(在C++中,以及在内存方面)合法吗?

不,如果您使用rvalue引用是合法的:

代码语言:javascript
复制
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是一个lvalue (它有一个名称),所以您可以获取它的地址,加上它是可变的。

票数 6
EN

Stack Overflow用户

发布于 2017-03-12 20:16:41

用简单的英语:

代码语言:javascript
复制
void PrintAddress(const std::string& lref) {
  std::cout << &lref << std::endl;
}

任何具有名称的对象都是lvalue,因此在上述函数范围内对lref的任何使用都是lvalue使用。

当您用以下方法调用函数时:

代码语言:javascript
复制
PrintAddress(lref.substr() /* temporary of type std::string */)

当然,lref.substr()生成一个临时的rvalue,但是rvalues可以绑定到const引用或rvalue引用(使其生命期延长)。

即使您提供了一个rvalue重载,但实际上它有一个名称,它是其范围内的“某个东西的值”,例如:

代码语言:javascript
复制
#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++中,任何具有名称的对象(无论是值类型、引用类型还是指针类型)都是lvalue。

也要知道一些表达也会产生lvalue。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42752455

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档