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

如何从内存池返回带自定义删除器、指向抽象类型的std::unique_ptr

问题根源

编译失败的核心原因是std::unique_ptr的删除器属于其类型签名的一部分,代码中原定义的std::unique_ptr<Test, std::function<void(Test*)>>与ITestOwner中使用默认删除器的std::unique_ptr<ITest>是完全不兼容的两种类型,无法直接转移所有权。

可行实现方案

通过调整ITestOwner的智能指针定义,使用类型擦除的std::function作为删除器,同时封装自定义删除逻辑适配基类指针,即可实现需求。修改后可正常运行的完整代码如下:

#include <iostream>
#include <memory>
#include <functional>
#include <utility>

template <typename T>
class MemoryPool {
public:
    template <typename ... ARGS>
    T* create(ARGS&&... args) {
        std::cout << "MemoryPool::create()" << std::endl;
        return new T(std::forward<ARGS>(args)...);
    }
    
    void destroy(T* ptr) {
        std::cout << "MemoryPool::destroy()" << std::endl;
        delete ptr;
    }
};

class ITest {
public:
    ITest() {
        std::cout << "ITest::ITest()" << std::endl;
    }
    virtual ~ITest() {
        std::cout << "ITest::~ITest()" << std::endl;
    }
    
    virtual void sayHello() = 0;
};

class Test :public ITest {
public:
    Test() {
        std::cout << "Test::Test()" << std::endl;
    }
    ~Test() {
        std::cout << "Test::~Test()" << std::endl;
    }
    
    void sayHello() override { 
        std::cout << "Test says hello" << std::endl; 
    }
};

class ITestOwner {
public:
    // 修改构造函数参数类型,使用带类型擦除删除器的unique_ptr
    ITestOwner(std::unique_ptr<ITest, std::function<void(ITest*)>> ptr) : 
        _ptr(std::move(ptr)) 
    {
        std::cout << "ITestOwner::ITestOwner()" << std::endl;
    }
    
    ~ITestOwner() {
        std::cout << "ITestOwner::~ITestOwner()" << std::endl;
    }
    
    void sayHello() { _ptr->sayHello(); }
    
private:
    // 修改成员变量类型
    std::unique_ptr<ITest, std::function<void(ITest*)>> _ptr;
};

int main() {
    MemoryPool<Test> pool;
    
    // 直接构造指向ITest的unique_ptr,删除器中做安全类型转换
    std::unique_ptr<ITest, std::function<void(ITest*)>> ptr(pool.create(), [&pool](ITest* ptr){
        std::cout << "Custom Deleter" << std::endl;
        pool.destroy(static_cast<Test*>(ptr));
    });
    
    ITestOwner owner(std::move(ptr));
    
    owner.sayHello();
    
    return 0;
}
补充说明
  • 因为可以确认传入的ITest*一定是MemoryPool<Test>分配的Test类实例,所以用static_cast做向下转换是安全的,不需要额外的运行时检查。
  • 如果不想修改ITestOwner的定义,可以替换为std::shared_ptr实现:std::shared_ptr的删除器是类型擦除的,不属于类型签名的一部分,你可以直接构造std::shared_ptr<ITest>并传入自定义删除器,不需要修改持有类的定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 15:45:04