c++ - 使用内存池中的自定义删除器将 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 对象应该被返回到内存池中。
有没有办法做到这一点?
解决方案
该代码无法编译,因为您转发它时std::unique_ptr<ITest>
使用了该代码。它显然不能编译,因为调用 delete on而不是调用一些复杂的任意函数。ITestOwner
std::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 方开源库——它们有很多。