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

问题描述

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

考虑以下代码:

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()
    {}
};

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

标签: c++inheritanceconstructortype-conversionthis

解决方案


一般来说,这是一种有点危险的模式。可以保持严格有效,但在显示的示例中,它实际上是标准不允许的Base1*转换。AnotherClass*

[class.cdtor]/2对将指针从派生类转换为基类给出了一些限制:

显式或隐式地将引用类对象的指针(glvalue)转换为指向X直接或间接基类的指针(引用),其所有直接或间接基类BX构造X和构造直接或间接派生B应该已经开始并且这些类的销毁应该没有完成,否则转换会导致未定义的行为。

当评估子对象的初始化程序“ this”时, 的构造已经开始,但其子对象的构造尚未开始。但是由于继承树中没有其他派生自的类,因此to转换是可以的。如果父类构造函数尚未启动,则转换为指向祖父类的指针是不行的;如果祖父类是虚拟基类,则在继承它的最后一个中间类开始构建之前不允许转换!Base0DerivedBase1Base1Derived*Base1*this

At first, that converted pointer points at an object whose (non-trivial) construction has not yet started, so it's subject to the restrictions in [class.cdtor]/1 and [basic.life]/6. Mostly, you can't get at any of its base class subobjects or members yet. Copying that pointer, without any further implicit base class pointer conversions, is almost all you can legally do with it. So the example's implicit conversion from Base1* to AnotherClass* results in undefined behavior. It would be okay, though, if the anotherObj member had exactly the same type Base1*.


推荐阅读