【发布时间】: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;是动态初始化,所以它发生在p1p2被初始化之后。这似乎也不相关,如果前面的引用被正确解释,那么代码有 UB,故事结束 -
我想知道
&bobj.a是否算作“引用”bobj.a,我不明白为什么这会导致UB,因为它是不断初始化的。 -
@DmitryFucintv 我认为
B bobj;是动态的。它不是零也不是常量(构造函数Y()甚至不可见,它可能包含在编译时无法解析的调用)
标签: c++ constructor