如何在std :: unique_ptr中使用boost :: object_pool?

时间:2015-03-03 22:37:12

标签: c++ c++11 boost visual-studio-2013 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;
 };

我正在努力确保

  1. Foo类型的对象仅由Bar,
  2. 类型的对象分配和拥有
  3. 它们存储在池中,
  4. 通过独特的指针访问它们。
  5. 使用Visual Studio编译器遇到以下问题

    1. 如果我删除默认运算符new(标有***的行),则不会编译placement new(标有111的行)。我做错了还是VS限制?

    2. 我想,为了创建一个在池中分配的正确unique_ptr,我需要提供对池删除器的访问。标记为222的行是我尝试这样做的。编译器也不接受它。什么是正确的语法?

1 个答案:

答案 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);
}

Live demo

或者,明确调用全局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
  }
}

Live demo