如何在C++基类中自动感知派生类的销毁?
如何在派生类销毁前让基类提前执行指针移除操作?
核心问题
C++中对象销毁时,派生类析构函数会先于基类析构函数执行。我们希望在派生类开始销毁时自动通知基类调用其成员函数(比如从有效对象表中移除自身指针),但手动在每个派生类的析构函数中调用基类通知函数的方式,要求所有继承该基类的用户都必须牢记添加这段代码,容易遗漏,因此需要更可靠的实现方式。
背景场景
正在构建一个多线程框架:
- 继承自
GeneralObject类的MyObject类对象会被主线程和生产者线程同时访问。 - 主线程销毁对象时,
MyObject的析构函数先执行,随后GeneralObject的析构函数才会将自身指针从存储所有有效GeneralObject多态对象的valid-object-table中移除,以此阻止生产者线程访问已销毁的对象。 - 问题在于:
MyObject析构函数执行后到GeneralObject析构函数执行前的短暂间隙内,valid-object-table中存储的指针已经成为悬空指针,虽然后续会被移除,但生产者线程可能在此期间访问该对象,存在严重的线程安全隐患。我们需要让GeneralObject的移除函数在MyObject开始销毁时就立即执行。
原方案的问题
最初考虑在派生类析构函数中手动调用基类的移除函数,但正如@user17732522指出:一旦进入MyObject的析构函数,对象已经处于销毁过程中,此时对象指针已经失效,即使调用移除函数,也无法完全避免生产者线程在间隙内访问的风险,原方案本质上是不安全的。
最终实现方案
采用@HolyBlackCat提出的RAII包装对象方案,在MyObject的析构函数被调用前,提前执行基类的指针移除操作:
实现思路
通过一个通用的包装类,将目标对象的生命周期与基类的注册/移除操作绑定:
- 包装类构造时,自动将内部对象注册到
valid-object-table中。 - 包装类销毁时,先调用基类的移除函数将对象从
valid-object-table中移除,再销毁内部的目标对象(此时才会依次执行派生类和基类的析构函数)。
示例代码
#include <utility> class GeneralObject { public: void register_self() { // 将this指针加入valid-object-table的逻辑 } void remove_self() { // 将this指针从valid-object-table移除的逻辑 } virtual ~GeneralObject() = default; }; class MyObject : public GeneralObject { // 派生类的成员和逻辑 }; template<typename T> class ObjectWrapper { public: // 转发构造参数给内部对象 template<typename... Args> ObjectWrapper(Args&&... args) : obj(std::forward<Args>(args)...) { static_cast<GeneralObject*>(&obj)->register_self(); } // 先执行移除操作,再销毁内部对象 ~ObjectWrapper() { static_cast<GeneralObject*>(&obj)->remove_self(); // obj的析构函数会在此之后自动调用 } // 提供对内部对象的访问接口 T* operator->() { return &obj; } const T* operator->() const { return &obj; } T& operator*() { return obj; } const T& operator*() const { return obj; } private: T obj; }; // 使用方式 int main() { ObjectWrapper<MyObject> obj; // 通过obj访问MyObject的成员,比如obj->some_method(); // 当obj离开作用域时,先调用remove_self(),再销毁MyObject return 0; }
这种方式无需派生类开发者手动添加任何析构代码,完全由包装类自动处理注册和移除逻辑,从根源上避免了遗漏的风险,同时彻底消除了对象销毁过程中的悬空指针间隙。
内容的提问来源于stack exchange,提问作者Jin Kim
相关产品推荐
相关产品推荐

