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

如何在含保护虚析构的只读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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:27:48