首页 > 解决方案 > 使用内存池中的自定义删除器将 std::unique_ptr 返回到抽象类型

问题描述

假设我有一个模板化的 MemoryPool 类,一个函数 create(...)(它返回一个指向新分配的 T 类型对象的指针)和一个函数 destroy(T*)(它销毁并将内存返回到池中)。

我想创建一个 std::unique_ptr ,它“拥有”池创建的指针并将指针返回到池,因此需要一个自定义删除器。

问题是,如果池包含具体对象并且我想将 std::unique_ptr 传递给该对象的抽象接口,我该如何进行这项工作。

这是一个无法编译的示例:

#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:
    ITestOwner(std::unique_ptr<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> _ptr;
};

int main() {
    MemoryPool<Test> pool;
    
    std::unique_ptr<Test, std::function<void(Test*)>> ptr(pool.create(), [&pool](Test* ptr){
        std::cout << "Custom Deleter" << std::endl;
        pool.destroy(ptr);
    });
    
    ITestOwner owner(std::move(ptr));
    
    owner.sayHello();
    
    return 0;
}

请记住,我真正的 MemoryPool 类实际上将充当普通内存池,而不是像我所做的那样使用 new/delete。

在此示例中,ITestOwner 应将 std::unique_ptr 的所有权接管给 ITest 抽象对象。那么,当 ITestOwner 被销毁时,智能指针也会被销毁,Test 对象应该被返回到内存池中。

有没有办法做到这一点?

标签: c++c++17unique-ptr

解决方案


该代码无法编译,因为您转发它时std::unique_ptr<ITest>使用了该代码。它显然不能编译,因为调用 delete on而不是调用一些复杂的任意函数。ITestOwnerstd::unique_ptr<Test, std::function<void(Test*)>>std::unique_ptr<ITest>ITest

您需要使用unique_ptr<ITest, function<void(ITest*)>>它才能工作,另外添加一些难看的转换代码 from function<void(Test*)>to function<void(ITest*)>... 我会说这根本不好。unique_ptr被设计为简单高效 - 析构函数应该包装基本功能,但对于复杂的目的它不够方便。

基本上,unique_ptr不是为这个任务而设计的。它应该是轻量级的,而您已经使用了像std::function这样的繁重功能破坏了整个目的。相反,您可以使用shared_ptr哪种类型来擦除删除器并将其隐藏——因此您无需担心。如果您仍想将用户限制为唯一所有权,您肯定可以找到其他实现您想要的智能指针的第 3 方开源库——它们有很多。


推荐阅读