在对象构造期间将指向尚未构造的子对象的指针传递给另一个子对象的构造函数是否危险?

Is it dangerous to pass a pointer to a subobject that is not constructed yet to a constructor of another subobject during the object construction?

子对象在构造之前不会被使用,只会存储指向它的指针。

考虑以下代码:

class Base1;

class Base0 
{
public:
    Base0(Base1* obj1) : 
        anotherObj(new AnotherClass(obj1)) // only saves the pointer, doesn't use the object 
    {}

    AnotherClass* anotherObj;
};

class Base1 { /*...*/ };

class Derived : public Base0, public Base1
{
public:
    Derived() :
        Base0(this), // expecting an implicit conversion of Derived* to Base1*
        Base1()
    {}
};

是否可以在任何基类构造发生之前将此指针向上转换为任何基类并获得有效指针?那么虚拟继承等更复杂的情况呢?

总的来说,这是一种有点危险的模式。可以使事情严格有效,但在所示示例中,实际上是标准不允许的从 Base1*AnotherClass* 的转换。

[class.cdtor]/2 对将指针从派生 class 转换为基数 class:

给出了一些限制

To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior.

Base0 subobject 的初始化器“this”被求值时,Derived 的构造已经开始,但是它的 Base1 subobject 还没有开始。但是由于继承树中没有其他 class 派生自 Base1,因此 Derived*Base1* 的转换是可以的。如果 parent class 构造函数尚未启动,则将 this 转换为指向 grandparent class 的指针是不可行的;如果grandparent class是一个虚拟基class,则在继承它的最后一个中间体class开始构建之前不允许转换!

起初,那个转换后的指针指向一个object,它的(non-trivial)构造还没有开始,所以它受到[class.cdtor]/1 and [basic.life]/6中的限制。大多数情况下,您还无法访问它的任何基础 class 子object 或成员。复制该指针,无需任何进一步的隐式基 class 指针转换,几乎是您可以合法地使用它进行的所有操作。因此,该示例从 Base1*AnotherClass* 的隐式转换会导致未定义的行为。不过,如果 anotherObj 成员的类型完全相同 Base1*.