C++ object-pool that provides items as smart-pointers that are returned to pool upon deletion

前端 未结 4 1861
渐次进展
渐次进展 2020-12-12 18:48

I\'m having fun with c++-ideas, and got a little stuck with this problem.

I would like a LIFO class that manages a pool of resources. When a resource is

4条回答
  •  旧时难觅i
    2020-12-12 19:11

    Naive implementation

    The implementation uses unique_ptr with a custom deleter that returns objects to the pool. Both acquire and release are O(1). Additionally, unique_ptr with custom deleters can be implicitly converted to shared_ptr.

    template 
    class SharedPool
    {
     public:
      using ptr_type = std::unique_ptr >;
    
      SharedPool() {}
      virtual ~SharedPool(){}
    
      void add(std::unique_ptr 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(ptr));
                     });
        pool_.pop();
        return std::move(tmp);
      }
    
      bool empty() const {
        return pool_.empty();
      }
    
      size_t size() const {
        return pool_.size();
      }
    
     private:
      std::stack > pool_;
    };
    

    Example usage:

    SharedPool pool;
    pool.add(std::unique_ptr(new int(42)));
    pool.add(std::unique_ptr(new int(84)));
    pool.add(std::unique_ptr(new int(1024)));
    pool.add(std::unique_ptr(new int(1337)));
    
    // Three ways to express the unique_ptr object
    auto v1 = pool.acquire();
    SharedPool::ptr_type v2 = pool.acquire();    
    std::unique_ptr > v3 = pool.acquire();
    
    // Implicitly converted shared_ptr with correct deleter
    std::shared_ptr v4 = pool.acquire();
    
    // Note that adding an acquired object is (correctly) disallowed:
    // pool.add(v1);  // compiler error
    

    You might have caught a severe problem with this implementation. The following usage isn't unthinkable:

      std::unique_ptr< SharedPool > pool( new SharedPool );
      pool->add(std::unique_ptr(new Widget(42)));
      pool->add(std::unique_ptr(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
    

    We need a way to keep alive information necessary for the deleter to make the distinction

    1. Should I return object to pool?
    2. Should I delete the actual object?

    One way of doing this (suggested by T.C.), is having each deleter keep a weak_ptr to shared_ptr member in SharedPool. This lets the deleter know if the pool has been destroyed.

    Correct implementation:

    template 
    class SharedPool
    {
     private:
      struct External_Deleter {
        explicit External_Deleter(std::weak_ptr* > pool)
            : pool_(pool) {}
    
        void operator()(T* ptr) {
          if (auto pool_ptr = pool_.lock()) {
            try {
              (*pool_ptr.get())->add(std::unique_ptr{ptr});
              return;
            } catch(...) {}
          }
          std::default_delete{}(ptr);
        }
       private:
        std::weak_ptr* > pool_;
      };
    
     public:
      using ptr_type = std::unique_ptr;
    
      SharedPool() : this_ptr_(new SharedPool*(this)) {}
      virtual ~SharedPool(){}
    
      void add(std::unique_ptr t) {
        pool_.push(std::move(t));
      }
    
      ptr_type acquire() {
        assert(!pool_.empty());
        ptr_type tmp(pool_.top().release(),
                     External_Deleter{std::weak_ptr*>{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* > this_ptr_;
      std::stack > pool_;
    };
    

提交回复
热议问题