You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++基类中自动感知派生类的销毁?

如何在派生类销毁前让基类提前执行指针移除操作?

核心问题

C++中对象销毁时,派生类析构函数会先于基类析构函数执行。我们希望在派生类开始销毁时自动通知基类调用其成员函数(比如从有效对象表中移除自身指针),但手动在每个派生类的析构函数中调用基类通知函数的方式,要求所有继承该基类的用户都必须牢记添加这段代码,容易遗漏,因此需要更可靠的实现方式。

背景场景

正在构建一个多线程框架:

  • 继承自GeneralObject类的MyObject类对象会被主线程和生产者线程同时访问。
  • 主线程销毁对象时,MyObject的析构函数先执行,随后GeneralObject的析构函数才会将自身指针从存储所有有效GeneralObject多态对象的valid-object-table中移除,以此阻止生产者线程访问已销毁的对象。
  • 问题在于:MyObject析构函数执行后到GeneralObject析构函数执行前的短暂间隙内,valid-object-table中存储的指针已经成为悬空指针,虽然后续会被移除,但生产者线程可能在此期间访问该对象,存在严重的线程安全隐患。我们需要让GeneralObject的移除函数在MyObject开始销毁时就立即执行。

原方案的问题

最初考虑在派生类析构函数中手动调用基类的移除函数,但正如@user17732522指出:一旦进入MyObject的析构函数,对象已经处于销毁过程中,此时对象指针已经失效,即使调用移除函数,也无法完全避免生产者线程在间隙内访问的风险,原方案本质上是不安全的。

最终实现方案

采用@HolyBlackCat提出的RAII包装对象方案,在MyObject的析构函数被调用前,提前执行基类的指针移除操作:

实现思路

通过一个通用的包装类,将目标对象的生命周期与基类的注册/移除操作绑定:

  1. 包装类构造时,自动将内部对象注册到valid-object-table中。
  2. 包装类销毁时,先调用基类的移除函数将对象从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 00:51:16