如何使用 boost::object_pool 和 std::unique_ptr?
How to use boost::object_pool with std::unique_ptr?
这是一个由以下代码说明的两部分问题:
#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;
};
我正在努力确保
- Foo 类型的对象仅由 Bar 类型的对象分配和拥有,
- 它们存储在池中,
- 它们通过唯一指针访问。
使用Visual Studio编译器我运行陷入以下问题
如果我删除默认的 operator new(标有 *** 的行),则 placement new(标有 111 的行)不会编译。是我做错了什么还是VS限制?
我想,为了在池中分配适当的 unique_ptr,我需要提供对池删除器的访问权限。标记为 222 的行是我尝试这样做的。编译器也不接受它。正确的语法是什么?
boost::object_pool::destroy
是一个非static
成员函数,所以需要在object_pool
实例上调用。此外,删除器是 unique_ptr
类型的一部分,因此必须相应地声明您的 FooHandle
别名。此外,您的 addFoo()
函数在应该返回 FooHandle
时返回 Foo*
。
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
打包删除器远非理想。避免这种情况的一种方法是创建一个仿函数类型来存储对 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
}
}
这是一个由以下代码说明的两部分问题:
#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;
};
我正在努力确保
- Foo 类型的对象仅由 Bar 类型的对象分配和拥有,
- 它们存储在池中,
- 它们通过唯一指针访问。
使用Visual Studio编译器我运行陷入以下问题
如果我删除默认的 operator new(标有 *** 的行),则 placement new(标有 111 的行)不会编译。是我做错了什么还是VS限制?
我想,为了在池中分配适当的 unique_ptr,我需要提供对池删除器的访问权限。标记为 222 的行是我尝试这样做的。编译器也不接受它。正确的语法是什么?
boost::object_pool::destroy
是一个非static
成员函数,所以需要在object_pool
实例上调用。此外,删除器是 unique_ptr
类型的一部分,因此必须相应地声明您的 FooHandle
别名。此外,您的 addFoo()
函数在应该返回 FooHandle
时返回 Foo*
。
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
打包删除器远非理想。避免这种情况的一种方法是创建一个仿函数类型来存储对 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
}
}