【问题标题】:what are rules about when the return type is reference返回类型为引用时的规则是什么
【发布时间】:2020-04-03 03:35:54
【问题描述】:
#include <iostream>
int func0(){
  int a = 0;
  return a;
}
int&& func1(){
   int a = 0;
   return a;
}
int main(){
  int&& result0 = func0();
  int&& result1 = func1();
}

return statement 规则为:

  1. 函数通过 return 语句返回给它的调用者。
  2. [...] return 语句通过操作数的复制初始化来初始化(显式或隐式)函数调用的glvalue 结果或prvalue 结果对象

关于如何初始化函数调用的对象的规则只有#2。

我们知道表达式func0() 是prvalue。引用result0需要绑定一个对象,所以temporary materialization conversion要把prvalue转换成xvalue,所以临时对象作为prvalue结果对象是从return的操作数初始化的,然后引用reusult0绑定到临时对象。

但我们知道result1 是引用,func1 的返回类型也是引用。对于这种情况,[stmt.return]并没有明确涵盖这种情况,因为result1是引用而不是object(既不是glvalue reuslt对象也不是prvalue结果对象),那么规则是什么关于这个案子?如果我遗漏了什么,请纠正我。

【问题讨论】:

  • 为什么要单独问这个?考虑到您的问题围绕退货声明规则,您可以将这个疑问添加到之前的 question
  • @Anirban166 不同意 - 该网站使用“每个问题 1 个问题”格式。这个关于通过引用返回的问题与其他问题有很大不同
  • @Anirban166 我认为它们是不同的问题。所以我打开一个新帖子

标签: c++ return c++17 language-lawyer


【解决方案1】:

你对result0的分析是正确的。

但在result1 案例中没有临时实现。 “glvalue 结果”是从操作数a 复制初始化的引用,复制初始化相同类型的引用意味着引用直接绑定(dcl.init.ref/5,通过 dcl.init /17.2)。然后result1 绑定到glvalue 结果。

这会创建一个悬空引用; return 语句被明确排除在生命周期扩展规则 (class.temporary/6.2) 之外。

int result2 = func1(); 的情况下,glvalue 结果(引用)使用结果对象result2 进行左值到右值转换,这会导致未定义的行为,因为glvalue 结果是悬空的。

【讨论】:

  • 所以关键是glvalue reuslt不代表glvalue reuslt object?我误解了标准所说的,我把glvalue reuslt当作glvalue reuslt object...
  • @jackX glvalue 结果可能是也可能不是 object 。在这种情况下,它是一个引用,在int result2 = func1(); 的情况下,它将是一个对象。
  • 对不起,对于int result2 = func1();,我认为result2也是prvalue reuslt对象,因为为了初始化,左值到右值的转换应该用于将glvalue func1()转换为prvalue跨度>
  • @jackX result2 是一个左值,因为它有一个 name 。 result2a 复制初始化,这涉及到a 的左值到右值转换(即检索a 的存储值)
  • 例如int&amp;&amp; a = 0; int b = a;你认为b是prvalue reuslt对象吗?我认为是,因为a是一个glvalue,因此需要将其转换为prvalue以进行初始化。The result object of a prvalue is the object initialized by the prvalue所以我认为b是。如果我误解了,请纠正我。
【解决方案2】:

我们知道表达式func0 是prvalue

不正确。 func0(函数名表达式)是一个左值。您正在考虑func0()(函数调用表达式),这确实是一个prvalue。该段的其余部分是正确的。

我并没有真正遵循您的第二段,所以让我说一下:

func1() 是一个 xlvalue,引用 result 将绑定到该 xlvalue。

非常重要:因为您要返回对自动存储变量的引用,所以您会留下一个悬空引用。

【讨论】:

  • @bolov 是的,谢谢,我写错了,func0() 是prvalue
  • 关于第二段,我想我误解了glvalue result,到目前为止我把glvalue result当作glvalue result object
【解决方案3】:

对于这种情况,[stmt.return] 没有明确涵盖这种情况,因为 result1 是引用而不是对象(glvalue reuslt 都不是 对象或纯右值结果对象),...

不,它涵盖了。注意规则说“g​​lvalue result or prvalue result object”,而不是“glvalue result object or prvalue result object”。见[basic.lvalue]/5

glvalue 的 result 是表达式所表示的实体。这 prvalue 的 result 是表达式存储到其 语境;类型为 cv void 的纯右值没有结果。 prvalue 其结果是值 V 有时被称为具有或命名 值 V. prvalue 的 result 对象 是初始化的对象 prvalue; ...

所以func1()的结果的引用实体被初始化为a

【讨论】:

  • 是的,我误解了glvalue reuslt,到目前为止我把glvalue reuslt当成glvalue reuslt object,所以这是重点
  • 所以glvalue reuslt 表示identity of an object?
  • @jackX "glvalue 的结果是表达式表示的实体",实体不一定是对象。
  • 你能在标准中给出一个关于这个的链接吗?参考是glvalue结果吗?
  • @xskzr 只讲实体是怎样的,不是说glvalue结果是实体,哪里来的句子“The result of a glvalue is the entity by the expression”出自?跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-16
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多