【问题标题】:Referring member before execution of not trivial constructor在执行不平凡的构造函数之前引用成员
【发布时间】:2018-04-11 10:43:52
【问题描述】:

我阅读了 c++ 11 标准草案(N3242 修订版)并遇到以下声明:

(12.7 构造和破坏)。对于具有非平凡构造函数的对象,引用该对象的任何非静态成员或基类 在构造函数开始执行之前会导致未定义的行为。

据我了解,Foo 的默认构造函数具有未定义的行为(在代码段 i(&a.i)? Foo 的构造函数不是微不足道的(因为它是用户定义的),我指的是成员 a 在执行构造函数之前。

struct A
{
    int i;
};

struct Foo
{
    A a;
    int* i;
    Foo() : a(), i(&a.i)
    {}
};

UPD:int* 类型的成员的用法可能信息量不大(例如,int 类型更适合)

【问题讨论】:

  • “我指的是在构造函数执行之前的成员 a。” 不,你不是。你刚刚用a() 构建了它。 a.i 未初始化,但获取地址是可以的。
  • @underscore_d 实际上,由于 a 在构造函数初始化列表中是 value initialized,所以 a.i 的值被明确定义为零(整个结构 a 及其所有成员也是初始化值)。
  • @LmTinyToon 至于您的问题,在构造函数初始化程序中列出内存中所有 exists 成员。它们可能没有被初始化,但它们确实作为周围 Foo 对象的一部分存在(在这种情况下)。
  • @LmTinyToon 即使在这种情况下也没关系,因为初始化是按照在类中声明成员变量的顺序进行的。这意味着a 将被完全初始化,包括a.i,因此引用它并将其用作值是可以的。
  • @LmTinyToon 您的示例中没有任何内容与您对标准的引用相矛盾。同样,如果一个对象在其自己的构造函数初始化列表中对其自己的成员执行任何操作是非法的,则该语言将不存在。

标签: c++ c++11 constructor language-lawyer


【解决方案1】:

据我了解,Foo 的默认构造函数具有未定义的行为(在代码段 i(&a.i)? 中?

没有。您引用的措辞使用“在构造函数开始执行之前”这一短语。但是当我们在 mem-initializer 中初始化 i 时,我们正在这样做 after a 已经被构造(因为 a 在 @987654326 之前声明@),所以这很好。

此外,即使两个成员互换,程序仍然可以正常运行,因为A 没有非平凡的构造函数。

如果您查看该部分中的示例,它们会阐明措辞的意图。特别是second example

struct W { int j; };
struct X : public virtual W { };
struct Y {
  int* p;
  X x;
  Y() : p(&x.j) {   // undefined, x is not yet constructed
    }
};

X 有一个非平凡的构造函数(因为virtual 基数),所以我们在构造它之前引用x,但是p 的初始化就是这样做的。因此,UB。

【讨论】:

  • 据我了解,标准语句是指成员a的构造函数而不是Foo
  • @LmTinyToon 我不明白这个问题。该声明在这里根本不适用 - 如果您在构造 Foo 对象之前可能访问 Foo 的成员,它将适用。在Foo 中,我们没有任何具有重要构造函数的成员,因此我们不会做错任何事情——就本条款而言。
猜你喜欢
  • 2019-07-27
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
相关资源
最近更新 更多