3.8/1 说:
T 类型对象的生命周期
开始于: — 正确储存
T 型的对齐方式和尺寸为
获得,并且 - 如果 T 是类类型
带有一个不平凡的构造函数(12.1),构造函数调用已完成.
3.8/5 说:
在对象的生命周期开始之前但在分配该对象将占用的存储空间之后或者,在对象的生命周期结束之后且在该对象占用的存储空间之前
重新使用或释放,指向对象将位于或曾经位于的存储位置的任何指针
可以使用,但只能以有限的方式使用。这样的指针指的是分配的存储空间(3.7.3.2),并使用
指针就好像指针是 void* 类型一样,是明确定义的。这样的指针可以被取消引用,但是
生成的左值只能以有限的方式使用,如下所述。
“低于”为 3.8/6:
这样的左值指的是分配的存储(3.7.3.2),并使用左值的属性,这些属性不
取决于它的值是否明确定义。
...然后是你不能做的事情的清单。绑定到对相同派生类型的引用不属于其中。
我在其他地方找不到任何可能使您的代码无效的内容。值得注意的是,尽管 8.3.2/4 中有以下短语:
引用应初始化为
引用有效的对象或函数。
似乎没有任何“有效对象”的定义可言。
于是,经过一番来回之后,我必须得出结论:这是合法的.
当然,这并不是说这是一个好主意! 它看起来仍然是一个糟糕的设计。
例如,如果您稍后更改基本构造函数,并且以下任何内容变得相关(同样从 3.8/6 开始):
- 左值用于访问非静态数据成员或调用对象的非静态成员函数
- 左值隐式转换 (4.10) 为对基类类型的引用
- 左值用作 a 的操作数
static_cast
(5.2.9)(除非最终转换为char&
or unsigned char&
- 左值用作 a 的操作数
dynamic_cast
(5.2.7) 或作为操作数typeid
.
...那么你的程序将是未定义的,并且编译器可能不会为此发出任何诊断信息!
随机其他观察
我注意到其他几个有趣的在编译这个答案时发生的事情,这是一个分享它们的好地方。
首先,9.3.2 似乎留下了类型this
in a 构造函数初始化器意外未指定。奇怪!
其次,3.8/5(与我在 3.8/6 中引用的列表不同)对指针设置的标准包括:
如果该对象将是或曾经是
非POD类类型,该程序有
未定义的行为如果 [..]
指针隐式转换 (4.10)
指向基类类型的指针。
我相信这会导致以下看似无害的代码未定义:
struct A {
A(A* ptr) {}
};
struct B : A {
B() : A(this) {}
};
int main() {
B b;
}