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
相关产品推荐
相关产品推荐

