【问题标题】:Understanding class object construction理解类对象构造
【发布时间】:2014-08-24 10:35:03
【问题描述】:

我正在阅读 N3797 的第 12.7 条。举个例子:

struct X { int i; };
struct Y : X { Y(); };  // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; }; // non-trivial

extern B bobj;
B* pb = &bobj; //1
int* p1 = &bobj.a; //2 undefined, refers to base class member
int* p2 = &bobj.y.i; //3 undefined, refers to member’s member
A* pa = &bobj;
B bobj;
extern X xobj;
int* p3 = &xobj.i;
X xobj;

这个例子必须反映规则:

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

但我有一个疑问。如果实现不以静态方式对//1//2//3 执行动态初始化,我们在//2//3 没有未定义的行为,因为(3.6.2/1):

不断初始化:

[...]

——如果具有静态或线程存储持续时间的对象由 构造函数 初始化 调用,并且如果初始化完整表达式是一个常量初始化器 物体;

[...]

一起调用零初始化和常量初始化 静态初始化;所有其他初始化都是动态的 初始化。 静态初始化应该在之前进行 发生动态初始化。

也就是说,我们已经在非静态和基类之前调用​​了该构造函数。所以该示例的结果是实现定义的。

我的推理正确吗?

【问题讨论】:

  • 首先,不清楚你在问什么?我要注意的第二件事是,您不能执行“extern B bobj; B* pb = &bobj;”之类的操作因为这将是关于未解决的外部链接器错误,所以进一步的推理似乎是不必要的。
  • @ars 他后来定义了bobj,没关系
  • 我不明白你问题的第二部分; B bobj; 是动态初始化,所以它发生在 p1 p2 被初始化之后。这似乎也不相关,如果前面的引用被正确解释,那么代码有 UB,故事结束
  • 我想知道&bobj.a是否算作“引用”bobj.a,我不明白为什么这会导致UB,因为它是不断初始化的。
  • @DmitryFucintv 我认为B bobj; 是动态的。它不是零也不是常量(构造函数 Y() 甚至不可见,它可能包含在编译时无法解析的调用)

标签: c++ constructor


【解决方案1】:

“它也可以调用 constexpr 构造函数”,Y::Y() 不是 constexpr 构造函数,所以 B bobj 属于动态初始化。

【讨论】:

  • 基本思想是 B bobj 是动态初始化的,它按初始化顺序放在 p1 和 p2 之后。
  • 是的,我明白你想说的话。谢谢。
  • 还有一个问题。如果我们将默认构造函数声明为constexprB bobj 的初始化将以静态方式执行,不是吗?
  • 它也必须是 constexpr 构造函数。这意味着它可能无法访问任何不是常量的值。可以编写一个有条件的 constexpr 构造函数,其中一些参数会使其不是 constexpr。
猜你喜欢
  • 2015-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
相关资源
最近更新 更多