来自question,我更进一步:
C* c = static_cast<C*>(malloc(sizeof(C)));
如引用的问题所述,在调用构造函数之前访问* c(其成员)是未定义的行为。但是,指针本身当然是有效的。
现在在构造函数中,成员已经可用,我应该能够取消该地址。
综合起来,我得出以下结论:
class Y;
class X
{
Y& y;
public:
X(Y& y) : y(y) { } // non-trivial constructor!
};
class Y
{
X& x;
public:
Y(X& x) : x(x) { }
};
class Z
{
X x;
Y y;
public:
Z() : x(y), y(x) { }
};
只要X的构造函数不使用未初始化的Y引用而不是将其存储在某处。
这是正确的还是我监督了一些重点(从而再次产生UB)?如果我遗漏了某些东西,如果我使用指针而不是引用它会有所作为吗?
答案 0 :(得分:2)
应该没问题,但我们不允许在y
内使用X(Y& y)
因为它尚未初始化。
说不是UB的相关部分是:
3.7.5 / 6 n4140(重点是我的)
同样,在对象的生命周期开始之前但在之后 对象占用的存储空间已被分配,或之后 对象的生命周期已经结束,在存储之前就已经存在了 对象占用被重用或释放, 任何引用的glvalue 可以使用原始对象,但只能以有限的方式使用 。
y
是左值(也是glvalue),所以上面是相关的。使用这种参考访问变量是UB。
标准也说参考有效必须(8.3.2 / 5):
...应初始化引用以引用有效的对象或函数。
但我没有在标准中发现什么是valid object
。特别是它是否意味着它的构造函数已被调用。使用指针而不是引用似乎没有这个问题。
答案 1 :(得分:2)
这是合法的。为证明这一点,请参阅标准[basic.life]中的以下内容:
- 在对象的生命周期开始之前但在存储之后 对象将占用哪个已被分配,或之后 对象的生命周期已经结束,在存储之前就已经存在了 对象占用被重用或释放,任何引用的指针 可以使用对象将位于或位于的存储位置 但只是在有限的方面。对于正在建造的物体或 破坏,见12.7。否则,这样的指针指的是已分配 存储(3.7.4.2),并使用指针,就像指针一样 类型void *,定义明确。 ...
醇>...
- 同样,在对象的生命周期开始之前但在之后 对象占用的存储空间已被分配,或之后 对象的生命周期已经结束,在存储之前就已经存在了 对象占用被重用或释放,任何引用的glvalue 可以使用原始对象,但只能以有限的方式使用。对于对象 正在建设或破坏,见12.7。否则,这样的glvalue 指分配存储(3.7.4.2),并使用的属性 不依赖于其值的glvalue是明确定义的。
醇>...
仅提供参考属于“限制使用”的范围。 (对于生命周期尚未开始的对象)上面列出的标准。