【问题标题】:Reference to uninitialized object引用未初始化的对象
【发布时间】:2018-08-02 04:05:54
【问题描述】:

在解释问题之前,我想标记一下,我知道给定的示例是错误的代码。我已经在关注std::shared_ptr 以更合理的方式实现我的目标。这篇文章的原因只是我的好奇心和学习新事物的愿望。提前感谢您的帮助!

今天我的解析器代码有点乱。优化的东西等等。我专注于一些在解析过程中不必要地克隆的对象实例。我没有那么深思熟虑的想法来创建几个全局实例并通过静态方法访问它们。无论如何(强烈简化)我以这个有点有趣的案例结束:

class class_a
{
    class_a();
    class_a& referenceToObject;
};

class_a& getGlobalObject();

class_a::class_a()
:referenceToObject(getGlobalObject())
{}

class_a object;
class_a object2;

class_a& getGlobalObject()
{
    return object2;
}

这显然意味着我做了很多非常错误的事情,但是在这个分支上,优化是最重要的事情。

我很感兴趣在更广泛的编译器集合中这样的代码会发生什么。 GetGlobalObject() 正在返回对未调用构造函数的对象的引用。它仍然只返回引用 - 即指向编译时已知的内存空间(数据段或堆上的某处,不知道)的指针。

假设没有任何东西会调用任何方法或object2 引用的任何成员,这个示例是未定义的行为吗?

【问题讨论】:

  • @OlafDietsche 这些处理正在构造的对象的子对象,这在标准 IIRC 中有一个特殊情况。这是一个无关的对象。
  • object被构造时,对象object2存在(但处于不确定的未构造状态)。因此,我会说它是有效的,只要您在构造之前不对引用的对象做任何事情。如果你想要一个权威的答案,我建议添加language-lawyer 标签。
  • 在全局对象构造之前引用全局对象是C++中的一个经典问题。只要您仅引用它们的引用或指针,就可以了。一般情况下,无法保证全局对象的构建顺序,因为全局对象可能位于不同的翻译单元中。

标签: c++ reference initialization language-lawyer


【解决方案1】:

是的,传递对尚未构造的对象的引用是完全合法的,甚至以某些有限的方式使用此类引用。

[basic.life] ...类似地,在对象的生命周期开始之前但在对象将占用的存储空间已分配之后,或者在对象的生命周期结束之后并且在对象的存储空间之前占用被重用或释放,任何引用原始对象的glvalue都可以使用,但只能以有限的方式使用。对于正在构造或销毁的对象,请参阅 [class.cdtor]。否则,这样的glvalue指的是分配的存储([basic.stc.dynamic.allocation]),并且使用不依赖于其值的glvalue的属性是明确定义的。如果出现以下情况,则程序具有未定义的行为:
(7.1)glvalue用于访问对象,或者
(7.2) 泛左值用于调用对象的非静态成员函数,或者
(7.3) 泛左值绑定到对虚拟基类 ([dcl.init.ref]) 的引用,或者
(7.4) 泛左值用作dynamic_­cast ([expr.dynamic.cast]) 的操作数或typeid 的操作数。

只要你不做上述任何事情,你就没事了。

【讨论】:

  • 谢谢。我想知道(7.1)是否包括分配给(普通可复制的)对象?
  • @finnw 嗯,这是一个有趣的问题。我会说应该没问题。 “使用不依赖于其值的泛左值的属性是明确定义的”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
相关资源
最近更新 更多