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

C++中使用unique_ptr处理含protected析构函数的第三方类报错求助

解决std::unique_ptr管理拥有protected析构函数类的问题

问题背景

你尝试用std::unique_ptr管理第三方库中拥有protected析构函数的Parent类对象时遭遇编译错误,核心原因是std::unique_ptr默认使用的std::default_delete会直接执行delete操作,而外部代码无法访问Parent的protected析构函数。你的示例代码如下:

#include <memory>
#include <iostream>
using namespace std;
class Parent {
public:
    Parent () //Constructor
    {
        cout << "\n Parent constructor called\n" << endl;
    }
protected:
    ~ Parent() //Dtor
    {
        cout << "\n Parent destructor called\n" << endl;
    }
};
class Child : public Parent {
public:
    Child () //Ctor
    {
        cout << "\nChild constructor called\n" << endl;
    }
    ~Child() //dtor
    {
        cout << "\nChild destructor called\n" << endl;
    }
};
Parent* get() {
    return new Child();
}
int main(int argc, char const* argv[]) {
    Parent * p1 = get(); // 此语句正常
    std::unique_ptr<Parent> p2(get()); // 此语句报错
    return 0;
}

编译器报错的本质是:std::default_delete的operator()尝试调用Parent的析构函数,但该函数是protected权限,外部无法直接访问。


解决方案:自定义删除器

由于无法修改第三方库的Parent和Child类,我们可以给std::unique_ptr指定自定义删除器,利用Child的public析构函数完成对象销毁。

方法1:使用Lambda表达式作为删除器

这是最简洁的实现方式,直接在创建unique_ptr时定义删除逻辑:

int main(int argc, char const* argv[]) {
    Parent * p1 = get(); 
    // 自定义删除器:将Parent*安全转为Child*后执行删除
    std::unique_ptr<Parent, void(*)(Parent*)> p2(get(), [](Parent* ptr) {
        delete static_cast<Child*>(ptr);
    });
    return 0;
}

方法2:使用独立函数作为删除器

如果删除逻辑需要复用,可以单独定义删除函数:

// 自定义删除函数,可在多处复用
void delete_parent(Parent* ptr) {
    delete static_cast<Child*>(ptr);
}

int main(int argc, char const* argv[]) {
    Parent * p1 = get(); 
    std::unique_ptr<Parent, decltype(&delete_parent)> p2(get(), delete_parent);
    return 0;
}

方法3:使用std::function作为删除器类型(更灵活)

如果后续需要灵活调整删除逻辑,可以用std::function作为删除器类型:

#include <functional> // 需要包含此头文件

int main(int argc, char const* argv[]) {
    Parent * p1 = get(); 
    std::unique_ptr<Parent, std::function<void(Parent*)>> p2(get(), [](Parent* ptr) {
        delete static_cast<Child*>(ptr);
    });
    return 0;
}

方案可行性说明

  1. 第三方库的get()函数返回的是Child*转型为Parent*的指针,因此static_cast<Child*>(ptr)是类型安全的;
  2. Child的析构函数是public的,删除Child*时会先调用Child的析构,再自动触发Parent的protected析构——而子类Child有权访问父类的protected成员,因此这个调用是合法的。

内容的提问来源于stack exchange,提问作者alec.tu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:51:56