如何在含保护虚析构的只读Parent类中使用std::unique_ptr<Parent>
解决protected析构导致std::unique_ptr删除器无法删除的问题
这个问题的核心在于:Parent的protected析构函数只能被它自身或者子类访问,直接delete Parent*时,编译器会尝试调用Parent的析构函数——但哪怕你的Deleter继承了Parent也没用,因为protected成员的访问权限是基于访问者的类型,而非被访问对象的类型,Deleter只能访问自己内部的Parent部分,无权访问其他Parent对象的析构函数。
可行解决方案:将Parent指针转换为Derived指针再删除
因为你的std::unique_ptr<Parent>实际指向的是Derived对象,而Derived的析构函数是public的,我们可以在删除器里把Parent*安全转换为Derived*后再删除。这样做的逻辑是:
- 删除
Derived*会先调用Derived的public析构函数 Derived作为Parent的子类,有权调用Parent的protected析构函数,因此父类的析构会正常执行
修改后的删除器代码如下:
class Deleter { public: void operator()(Parent* ptr) { // 确认ptr实际指向Derived实例时,用static_cast高效转换 delete static_cast<Derived*>(ptr); } };
如果需要更安全的运行时检查(比如担心指针可能指向其他Parent子类),可以改用dynamic_cast做验证:
#include <cstdlib> // 用于std::abort class Deleter { public: void operator()(Parent* ptr) { Derived* derived_ptr = dynamic_cast<Derived*>(ptr); if (derived_ptr != nullptr) { delete derived_ptr; } else { // 处理错误情况,比如终止程序或抛出异常 std::abort(); } } };
测试代码验证
你可以用以下代码验证方案有效性:
#include <memory> class Parent{ // 不可修改的接口类 protected: virtual ~Parent(){}; public: // 其他接口 }; class Derived : public Parent{ // 自定义子类 public: virtual ~Derived(){} }; class Deleter { public: void operator()(Parent* ptr) { delete static_cast<Derived*>(ptr); } }; int main() { std::unique_ptr<Parent, Deleter> ptr(new Derived); // 离开作用域时,ptr会自动调用Deleter删除对象,无编译错误 return 0; }
这个方案完全不需要修改Parent类,符合你的限制条件,同时能正确完成对象的销毁流程。
内容的提问来源于stack exchange,提问作者Bin Zhou
相关产品推荐
相关产品推荐

