【问题标题】:Is a const reference bound to another reference which is cast from temporary a dangling reference?const 引用是否绑定到另一个从临时悬空引用投射的引用?
【发布时间】:2018-11-05 15:31:27
【问题描述】:

下面是sn-p的代码:

#include <iostream>
using namespace std;
struct B{
     int b;
     ~B(){cout <<"destruct B" << endl;}
};
B func(){
    B b;
    b.b = 1;
    return b;
}
int main(){
    const B& instance = (const B&)func(); //is `instance` a dangling reference?
    cout <<instance.b<<endl;
    return 0;
}

在this online compiler 中的输出是

destruct B
destruct B
1

所以返回值似乎比cout 操作更早被破坏。所以instance 似乎是一个悬空引用。

如果我们把const B&amp; instance = (const B&amp;)func();改成const B&amp; instance =func();,那么结果就是

destruct B
1
destruct B

作为补充,如果我在vs2015中测试代码,那么输出就是最后一个。但是,如果在gcc(before 4.6)中测试,输出的是前者,但在4.6之后的版本中输出的是后者。所以想知道是网上的编译器有错还是引用其实是悬空的。

【问题讨论】:

  • 你已经在标题中回答了你自己的问题:你的参考没有绑定到临时的。
  • 来自[class.temporary]/6: const int&amp; x = (const int&amp;)1; // temporary for value 1 has same lifetime as x
  • 啊,看起来该语言已通过缺陷报告wg21.link/cwg1299 追溯更改,因此 C++11 现在也可以“新”方式工作。 (DR 说以前只有纯右值被认为是“临时的”,而新规则更加宽松。)
  • @bigxiao:它曾经也是 C++11 中的一个悬空引用,直到 2017 年 7 月它才成为有效的 C++11。缺陷报告适用于旧版标准的方式非常模糊,因为正式它们只适用于唯一的当前标准。每份出版物均取代前一份出版物。 DR 的措辞不能从字面上适用于没有 glvalues 的 C++03,但您的供应商现在可以选择基于此 DR 延长 C++03 模式下的生命周期。我认为这是一个合理的解释。
  • @bigxiao:因为缺陷报告的工作方式。请注意,严格来说,它仍然存在于早期的 C++17 中——已发布的 C++17 包含旧的行为;缺陷报告仅在 C++17 完成后才被接受(例如,参见 wg21.link/N4659)。但“标准”是指“已发布的文档连同所有随后接受的缺陷报告”。

标签: c++ language-lawyer object-lifetime reference-binding


【解决方案1】:

根据最新草稿[class.temporary]/6(无关部分被我省略了):

第三个上下文是当一个引用被绑定到一个临时对象时。如果通过以下方式之一获得引用绑定到的泛左值,则引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在:

  • ...

  • const_cast ([expr.const.cast])、static_cast ([expr.static.cast])、dynamic_cast ([expr.dynamic.cast]) 或 reinterpret_cast ([expr.reinterpret.cast] ) 在没有用户定义的转换的情况下,将作为这些表达式之一的泛左值操作数转换为引用由操作数指定的对象或其完整对象或其子对象的泛左值,

  • ...

... [ 注意:显式类型转换 ([expr.type.conv], [expr.cast]) 被解释为一系列基本类型转换,如上文所述。 [ 示例:

const int& x = (const int&)1;  // temporary for value 1 has same lifetime as x

— 结束示例 ]— 结束注释 ]

您的代码格式正确。


在C++14之前,标准中对这种情况的措辞不清楚,存在缺陷问题1376。这个问题阐明了临时对象的生命周期在这种情况下应该不延长。但是,此说明已被问题 1299 所取代(即使在 C++17 中也没有包含其解决方案,但在当前草案中)。

所以你可以断定在issue 1299解决之前,这是GCC 4.6以后版本的一个bug。 GCC 还有一个bug report 52202。

【讨论】:

  • auto&amp;&amp; ref=std::forward(T{}); 怎么样? ref 悬空了吗?
  • @bigxiao 未扩展。因为 [class.temporary]/6 中的任何规则都不适用。
  • @bigxiao 临时生命周期延长规则是一堆非常特殊的情况,如果你跳出这些狭义的情况,你就不会被覆盖。 (如果你问我,那就太棘手了。)
猜你喜欢
  • 2021-10-13
  • 2019-07-02
  • 1970-01-01
  • 2015-05-23
  • 2013-07-04
  • 2018-08-22
  • 2016-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多