这是由以下代码说明的两部分问题:
#include <memory>
#include <vector>
#include <boost/pool/object_pool.hpp>
struct Foo {
Foo(int i) : _i(i) {}
void* operator new(size_t) = delete; // ***
int _i;
};
using FooHandle = std::unique_ptr<Foo>;
struct Bar {
Foo* addFoo(int i)
{
Foo* ptr = new (_fooPool.malloc()) Foo(i); // 111
return FooHandle(ptr,
&boost::object_pool<Foo,
boost::default_user_allocator_new_delete>::destroy); // 222
}
boost::object_pool<Foo> _fooPool;
};
我正在努力确保
使用Visual Studio编译器遇到以下问题
如果我删除默认运算符new(标有***的行),则不会编译placement new(标有111的行)。我做错了还是VS限制?
我想,为了创建一个在池中分配的正确unique_ptr,我需要提供对池删除器的访问。标记为222的行是我尝试这样做的。编译器也不接受它。什么是正确的语法?
答案 0 :(得分:2)
boost::object_pool::destroy
是非static
成员函数,因此需要在object_pool
实例上调用它。此外,删除者是unique_ptr
类型的一部分,因此必须相应地声明您的FooHandle
别名。此外,addFoo()
函数在返回Foo*
时会返回FooHandle
。
using FooHandle = std::unique_ptr<Foo, std::function<void(Foo *)>>;
FooHandle addFoo(int i)
{
Foo* ptr = new (_fooPool.malloc()) Foo(i);
return FooHandle(ptr, std::bind(&boost::object_pool<Foo>::destroy,
&_fooPool, std::placeholders::_1));
}
new
表达式的问题在于,delete
d new
重载隐藏了全局展示位置new
运算符。如果您也重载展示位置版本,代码也会编译。
static void* operator new(size_t count, void *p)
{
return ::operator new(count, p);
}
或者,明确调用全局operator new
Foo* ptr = ::new (_fooPool.malloc()) Foo(i);
您确定要打扰已删除的new
重载吗?这样做并不能阻止某人使用::new Foo(10)
在对象池之外分配Foo
。
作为T.C.在评论中提到,使用std::function
打包删除器远非理想。避免这种情况的一种方法是创建一个functor类型,该类型存储对object_pool
实例的引用,然后在该实例上调用destroy
。
struct FooDeleter
{
FooDeleter(boost::object_pool<Foo>& pool)
: pool(&pool)
{}
void operator()(Foo *p)
{
pool->destroy(p);
}
boost::object_pool<Foo> *pool;
};
using FooHandle = std::unique_ptr<Foo, FooDeleter>;
FooHandle addFoo(int i)
{
Foo* ptr = _fooPool.malloc();
if(ptr)
{
return FooHandle(::new (ptr) Foo(i), FooDeleter(_fooPool));
}
else
{
return FooHandle(nullptr, FooDeleter(_fooPool)); // or throw exception etc
}
}