重写自动对象的虚析构函数行为是否符合C++标准定义?
结论
你观察到的行为完全符合C++标准的规定,属于预期行为,差异来源于自动存储期(栈)对象和动态分配对象的销毁规则不同。
原理说明
- 虚析构函数的多态调用仅在通过基类指针/引用销毁对象时才会触发,走动态分发逻辑匹配实际对象类型的析构函数。
- 对于栈上声明的
type obj,编译器在编译阶段就已经确定其静态类型为type,自动变量的销毁逻辑是编译期静态绑定的,不管你后续是否通过Placement New在其内存上构造了派生类对象,销毁时都会直接调用静态类型对应的type::~type(),不会触发虚函数分发。 - 对于
new出来的动态分配对象,你通过基类指针pobj执行delete操作时,因为基类析构被声明为虚函数,会触发动态分发,匹配当前内存上实际存储的method_called类型的析构函数,所以你重写的派生类析构会被调用。
额外提示
你当前的实现方式存在未定义行为风险:在基类子对象的内存空间上直接构造派生类对象的操作,极易因为内存布局、对象生命周期管理不当触发非法访问问题。如果要实现「函数调用执行完成后触发指定逻辑」的需求,更稳妥的方案是使用RAII临时守卫对象,在守卫的析构函数中写后置逻辑,完全不需要修改原有对象的类型结构。
测试代码参考
#include <iostream> struct type { virtual ~type() { std::cout << "ordinary" << std::endl; } void method() { struct method_called : type { virtual ~method_called() override { std::cout << "method called" << std::endl; } }; this->~type(); new (this) method_called{}; } }; int main() { std::cout << "ordinary expected" << std::endl; { type obj; } std::cout << "method expected" << std::endl; { type obj; obj.method(); } std::cout << "method expected" << std::endl; type* pobj = new type{}; pobj->method(); delete pobj; }
内容的提问来源于stack exchange,提问作者AnArrayOfFunctions
相关产品推荐
相关产品推荐

