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

C++中如何在派生类默认析构前执行操作或优先调用基类析构?

解决方案

首先明确:C++的析构顺序是派生类先执行析构函数体,销毁自身成员,最后调用基类析构函数,这个规则无法直接修改。因此“让基类析构优先于派生类”无法实现,只能通过其他方式达成类似效果——确保子类的setDisable()操作在自身资源销毁前执行,避免线程安全问题。

以下是三种可行方案:

方案一:强制子类自定义析构函数(最安全)

通过纯虚析构+纯虚setDisable()强制派生类实现自定义析构,并在析构开头调用自身的setDisable(),确保操作在子类成员销毁前执行。

#include <mutex>
#include <atomic>

class A
{
public:
    // 纯虚析构必须提供定义
    virtual ~A() = 0;

protected:
    std::mutex m_lock;
    std::atomic<bool> m_enabled{true};
    // 纯虚函数强制派生类实现自身的禁用逻辑
    virtual void setDisable() = 0;
};

A::~A()
{
    std::lock_guard<std::mutex> guard(m_lock);
    m_enabled = false;
    // 基类自身的禁用操作
}

class B : public A
{
public:
    // 必须自定义析构函数
    ~B()
    {
        setDisable();
        // 可添加B的其他析构逻辑
    }

    void setDisable() override
    {
        std::lock_guard<std::mutex> guard(m_lock);
        m_enabled = false;
        // B特有的禁用操作,比如通知线程停止访问当前对象
        // 此时B的成员尚未销毁,可安全访问
    }
};

优点:完全保证线程安全,setDisable()可安全访问子类成员。
缺点:子类必须手动编写析构函数,无法依赖默认析构。

方案二:CRTP自动调用(适用于无子类成员依赖的场景)

利用奇异递归模板模式(CRTP)创建混入类,通过混入类的成员对象在基类析构阶段调用子类的setDisable()。此方案无需子类自定义析构,但setDisable()不能访问子类成员(此时子类成员已销毁)。

#include <mutex>
#include <atomic>

template <typename Derived>
class DisableMixin
{
protected:
    struct DisableHelper
    {
        Derived* owner;
        DisableHelper(Derived* o) : owner(o) {}
        ~DisableHelper()
        {
            owner->setDisable();
        }
    };

    DisableHelper m_helper;

    DisableMixin() : m_helper(static_cast<Derived*>(this)) {}
};

class A
{
public:
    virtual ~A()
    {
        std::lock_guard<std::mutex> guard(m_lock);
        m_enabled = false;
    }

protected:
    std::mutex m_lock;
    std::atomic<bool> m_enabled{true};
    virtual void setDisable() = 0;
};

class B : public A, public DisableMixin<B>
{
public:
    // 可直接使用默认析构函数
    void setDisable() override
    {
        std::lock_guard<std::mutex> guard(m_lock);
        m_enabled = false;
        // 仅执行不依赖B成员的操作,比如通知全局线程池
    }
};

优点:子类无需自定义析构,自动触发setDisable()。
缺点:setDisable()不能访问子类成员,否则会导致未定义行为。

方案三:自定义智能指针管理对象

通过自定义deleter,让智能指针在销毁对象前先调用setDisable(),再执行析构。此方案无需修改类的继承结构,但必须使用自定义智能指针管理对象。

#include <memory>
#include <mutex>
#include <atomic>

class A
{
public:
    virtual ~A()
    {
        std::lock_guard<std::mutex> guard(m_lock);
        m_enabled = false;
    }

    virtual void setDisable() = 0;

protected:
    std::mutex m_lock;
    std::atomic<bool> m_enabled{true};
};

class B : public A
{
public:
    void setDisable() override
    {
        std::lock_guard<std::mutex> guard(m_lock);
        m_enabled = false;
        // B特有的禁用操作
    }
};

// 自定义deleter,先调用setDisable再销毁对象
struct DisableDeleter
{
    template <typename T>
    void operator()(T* ptr) const
    {
        ptr->setDisable();
        delete ptr;
    }
};

// 定义自定义智能指针类型
using DisablePtr = std::unique_ptr<A, DisableDeleter>;

// 使用示例
int main()
{
    DisablePtr ptr(new B);
    // ptr销毁时,自动先调用B::setDisable(),再销毁对象
}

优点:无需修改类结构,自动触发setDisable()。
缺点:必须使用自定义智能指针,不能直接用裸指针或标准智能指针。

内容的提问来源于stack exchange,提问作者RLPMSK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:07:04