C++ 对象池,将项目作为智能指针提供,在删除时返回到池中

标签 c++ c++11 smart-pointers pool

我对 c++-ideas 很感兴趣,但遇到了这个问题。

我想要 LIFO管理资源池的类。 当请求资源时(通过 acquire() ),它将对象作为 unique_ptr 返回这在删除时会导致资源返回到池中。

单元测试是:

// Create the pool, that holds (for simplicity, int objects)
SharedPool<int> pool;
TS_ASSERT(pool.empty());

// Add an object to the pool, which is now, no longer empty
pool.add(std::unique_ptr<int>(new int(42)));
TS_ASSERT(!pool.empty());

// Pop this object within its own scope, causing the pool to be empty
{
  auto v = pool.acquire();
  TS_ASSERT_EQUALS(*v, 42);
  TS_ASSERT(pool.empty());
}

// Object should now have returned to the pool
TS_ASSERT(!pool.empty())

基本实现,将通过测试,除了重要的最终测试:

template <class T>
class SharedPool
{
 public:
  SharedPool(){}
  virtual ~SharedPool(){}

  void add(std::unique_ptr<T> t) {
    pool_.push(std::move(t));
  }

  std::unique_ptr<T> acquire() {
    assert(!pool_.empty());
    std::unique_ptr<T> tmp(std::move(pool_.top()));
    pool_.pop();
    return std::move(tmp);
  }

  bool empty() const {
    return pool_.empty();
  }

 private:
  std::stack<std::unique_ptr<T> > pool_;
};

问题:如何去做acquire()返回 unique_ptr删除者知道 this 的类型, 并调用 this->add(...) ,将资源返回到池中。

最佳答案

朴素的实现

实现使用 unique_ptr 和自定义删除器,将对象返回到池中。 acquirerelease 都是 O(1)。此外,带有自定义删除器的 unique_ptr 可以隐式转换为 shared_ptr

template <class T>
class SharedPool
{
 public:
  using ptr_type = std::unique_ptr<T, std::function<void(T*)> >;

  SharedPool() {}
  virtual ~SharedPool(){}

  void add(std::unique_ptr<T> t) {
    pool_.push(std::move(t));
  }

  ptr_type acquire() {
    assert(!pool_.empty());
    ptr_type tmp(pool_.top().release(),
                 [this](T* ptr) {
                   this->add(std::unique_ptr<T>(ptr));
                 });
    pool_.pop();
    return std::move(tmp);
  }

  bool empty() const {
    return pool_.empty();
  }

  size_t size() const {
    return pool_.size();
  }

 private:
  std::stack<std::unique_ptr<T> > pool_;
};

使用示例:

SharedPool<int> pool;
pool.add(std::unique_ptr<int>(new int(42)));
pool.add(std::unique_ptr<int>(new int(84)));
pool.add(std::unique_ptr<int>(new int(1024)));
pool.add(std::unique_ptr<int>(new int(1337)));

// Three ways to express the unique_ptr object
auto v1 = pool.acquire();
SharedPool<int>::ptr_type v2 = pool.acquire();    
std::unique_ptr<int, std::function<void(int*)> > v3 = pool.acquire();

// Implicitly converted shared_ptr with correct deleter
std::shared_ptr<int> v4 = pool.acquire();

// Note that adding an acquired object is (correctly) disallowed:
// pool.add(v1);  // compiler error

您可能已经发现此实现存在严重问题。以下用法并非不可想象:

  std::unique_ptr< SharedPool<Widget> > pool( new SharedPool<Widget> );
  pool->add(std::unique_ptr<Widget>(new Widget(42)));
  pool->add(std::unique_ptr<Widget>(new Widget(84)));

  // [Widget,42] acquired(), and released from pool
  auto v1 = pool->acquire();

  // [Widget,84] is destroyed properly, together with pool
  pool.reset(nullptr);

  // [Widget,42] is not destroyed, pool no longer exists.
  v1.reset(nullptr);
  // Memory leak

我们需要一种方法来保持删除器进行区分所需的信息

  1. 我应该将对象返回到池中吗?
  2. 我应该删除实际的对象吗?

这样做的一种方法(由 T.C. 建议)是让每个删除器在 SharedPool 中保留一个 weak_ptrshared_ptr 成员。这让删除者知道池是否已被销毁。

正确的实现:

template <class T>
class SharedPool
{
 private:
  struct External_Deleter {
    explicit External_Deleter(std::weak_ptr<SharedPool<T>* > pool)
        : pool_(pool) {}

    void operator()(T* ptr) {
      if (auto pool_ptr = pool_.lock()) {
        try {
          (*pool_ptr.get())->add(std::unique_ptr<T>{ptr});
          return;
        } catch(...) {}
      }
      std::default_delete<T>{}(ptr);
    }
   private:
    std::weak_ptr<SharedPool<T>* > pool_;
  };

 public:
  using ptr_type = std::unique_ptr<T, External_Deleter >;

  SharedPool() : this_ptr_(new SharedPool<T>*(this)) {}
  virtual ~SharedPool(){}

  void add(std::unique_ptr<T> t) {
    pool_.push(std::move(t));
  }

  ptr_type acquire() {
    assert(!pool_.empty());
    ptr_type tmp(pool_.top().release(),
                 External_Deleter{std::weak_ptr<SharedPool<T>*>{this_ptr_}});
    pool_.pop();
    return std::move(tmp);
  }

  bool empty() const {
    return pool_.empty();
  }

  size_t size() const {
    return pool_.size();
  }

 private:
  std::shared_ptr<SharedPool<T>* > this_ptr_;
  std::stack<std::unique_ptr<T> > pool_;
};

关于C++ 对象池,将项目作为智能指针提供,在删除时返回到池中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27827923/

相关文章:

c++ - Qt 智能指针相当于 Boost::shared_ptr ?

c++ - 段。 std::unique_ptr 和 ctor 的错误

c++ - boost shared_ptr 容器问题

c++ - std::vector、构造函数、对象

c++ - htmlcxx0.84编译错误

c# - C++ 右值引用和移动语义

c++ - 你如何保持由第二个元素排序的对的优先级队列?

c++ - 初始化类构造函数

使用函数指针调用成员函数的 C++ 语法

c++ - 缺少分号 : C++ or SWIG issue?