在析构函数中动态转换
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
对象。由于 Base2
与 Base1
没有任何关系,因此 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_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 [...] 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”,这与我上面的解释相符。
此代码合法吗?
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
对象。由于 Base2
与 Base1
没有任何关系,因此 dynamic_cast
returns 是一个空指针,并相应地输入条件。
编辑:standard says:
When a
dynamic_cast
is used in a constructor [...] or in a destructor [...], if the operand of thedynamic_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 thedynamic_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, thedynamic_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 thedynamic_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 [...] destructor's class. If the operand of thedynamic_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”,这与我上面的解释相符。