在析构函数中动态转换

Dynamic cast in destructor

此代码合法吗?

class Base1 {
};

class Base2 {
public:
    virtual ~Base2() {
        if (!dynamic_cast<Base1*>(this))
            std::cout << "aaaa" << std::endl;
    }
    Base2() {
    }
};

class MyClass: public Base1, public Base2 {
public:
    MyClass() {
    }
    virtual ~MyClass() {
        std::cout << "bbb" << std::endl;
    }
};

int main() {
    MyClass s;
    return 0;
}

我看到了两张照片,但我应该只看到一张。我猜动态演员是错误的。是否可以进行此类检查?

也许我自己找到了解决方案,回答是不,不可能:

来自bullet 6 of cppreference.com documentation

When dynamic_cast is used in a constructor or a destructor (directly or indirectly), and expression refers to the object that's currently under construction/destruction, the object is considered to be the most derived object. If new-type is not a pointer or reference to the constructor's/destructor's own class or one of its bases, the behavior is undefined.

另请参阅标准的 [class.cdtor]/6。

由于我在 Base2 析构函数中转换为 Base1,因此此行为未定义。

dynamic_cast在这种情况下定义明确。您观察到两行输出是正确的。

您错误地认为 Base2 的析构函数中 this 是派生的 class。此时derivedclass部分已经被销毁,不能再是derivedclass了。实际上,在Base2的析构函数运行时,this指向的对象只是一个Base2对象。由于 Base2Base1 没有任何关系,因此 dynamic_cast returns 是一个空指针,并相应地输入条件。

编辑:standard says

When a dynamic_­cast is used in a constructor [...] or in a destructor [...], if the operand of the dynamic_­cast refers to the object under construction or destruction, this object is considered to be a most derived object that has the type of the constructor or destructor's class. If the operand of the dynamic_­cast refers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the dynamic_­cast results in undefined behavior.

操作数this指的是被破坏的对象。因此,析构函数(Base2)的class被认为是最派生的class,这就是对象与目标类型(Base1*) 以任何方式。此外,操作数 this 的静态类型是 Base2* const,这显然是指向析构函数自身 class 的指针。因此,关于未定义行为的规则不适用。总之,我们有明确定义的行为。

我同意@j6t 的回答,但这里是对标准参考的扩展推理。

C++17 标准(最终草案)的 [class.cdtor]/5 和以前的标准版本对 dynamic_cast 对构造和销毁对象的特殊行为进行了描述。

特别是它说:

When a dynamic_­cast is used [...] in a destructor, [...], if the operand of the dynamic_­castrefers to the object under construction or destruction, this object is considered to be a most derived object that has the type of the [...] destructor's class. If the operand of the dynamic_­cast refers to the object under [...] destruction and the static type of the operand is not a pointer to or object of the [...] destructor's own class or one of its bases, the dynamic_­cast results in undefined behavior.

此处未定义的行为不适用,因为操作数是表达式 this,它通常具有指向析构函数自身 class 的指针类型,因为它出现在析构函数本身中。

但是,第一句指出 dynamic_cast 的行为就好像 *this 是类型 Base2 的最派生对象,因此转换为 Base1 可以永远不会成功,因为 Base2 不是从 Base1 派生的,并且 dynamic_cast<Base1*>(this) 总是 return 一个空指针,导致您看到的行为。


cppreference.com 声明如果强制转换的目标类型不是析构函数的 class 或其基类之一的类型,而不是将其应用于操作数类型,则会发生未定义的行为.我认为那只是一个错误。可能在要点 6 中提到的“new-type”应该是“expression”,这与我上面的解释相符。