Binglong's space

Random notes on computer, phone, life, anything

Posts Tagged ‘pool’

Resource Pool: Memory Pool etc

Posted by binglongx on August 8, 2025

If the model is that you keep tight control of the resources all the time, and only let the client gain access for some time period, you might do something like this:

#include <memory>   // std::unique_ptr
#include <vector>   // std::vector
#include <utility>  // std::swap, std::move
#include <cassert>  // assert


template<typename T> class Pool;

// represent reference to an object in pool 
template<typename T> class PooledObjectRef {
public:
    // empty
    PooledObjectRef() {}
    
    // move
    PooledObjectRef(PooledObjectRef&& other)
    : PooledObjectRef() {
        swap(other);
    }
    PooledObjectRef& operator = (PooledObjectRef&& other) {
        swap(other);
        return *this;
    }

    // cannot copy
    PooledObjectRef(const PooledObjectRef& other) = delete;
    PooledObjectRef& operator = (const PooledObjectRef& other) = delete;

    // has resource or not
    operator bool() const {
        return resource_ != nullptr;
    }
    
    // access the real resouce
    T& operator*() {
        return *resource_;
    }
    const T& operator*() const {
        return *resource_;
    }

    // return resource to pool
    void recycle();
    
    // automatically recycle
    ~PooledObjectRef() {
        recycle();
    }
    
public:
    void swap(PooledObjectRef& other) {
        std::swap(pool_, other.pool_);
        std::swap(resource_, other.resource_);
    }
    
private:
    friend class Pool<T>;
    
    PooledObjectRef(Pool<T>* pool, T* resource)
    : pool_(pool), resource_(resource) {
    }
    
    void wipe() {
        pool_ = nullptr;
        resource_ = nullptr;
    }
    
private:
    Pool<T>*    pool_ = nullptr;
    T*          resource_ = nullptr;
};

// manage a pool of resources
template<typename T> class Pool {
public:
    template<typename... ARGS>
    Pool(size_t n, ARGS&&... args) {
        for(size_t i = 0; i < n; ++i) {
            free_.push_back(std::make_unique<T>(std::forward<ARGS...>(args)...));
        }
    }
    
    PooledObjectRef<T> acquire() {
        if( not free_.empty() ) {
            used_.push_back( std::move(free_.back()) );
            free_.pop_back();
            return PooledObjectRef<T>{this, used_.back().get()};
        }
        return {};
    }
    
    bool recycle(PooledObjectRef<T>& obj) {
        if( obj.pool_ == this ) {
            auto it = std::ranges::find_if(used_, [&obj](auto& p) {
                return obj.resource_ = p.get();
            });
            if( it != free_.end() ) {
                free_.push_back( std::move(*it) );
                used_.erase(it);
                obj.wipe();
                return true;
            }
            else {
                assert(false);  // coding error
            }
        }
        else {
            assert(false);  // pass in object from different pool.
        }
        return false;
    }
    
    size_t available() const {
        return free_.size();
    }

    bool empty() const {
        return available() == 0u;
    }

private:
    std::vector<std::unique_ptr<T>> free_;
    std::vector<std::unique_ptr<T>> used_;
};

template<typename T>
inline void PooledObjectRef<T>::recycle() {
    if( pool_ ) {
        [[maybe_unused]] bool ok = pool_->recycle(*this);
        assert(ok); // should never fail
    }
}

int main() {
    Pool<int> pool(2, 42);

    assert(pool.available() == 2);
    {
        auto ptr = pool.acquire();
        assert(ptr && *ptr == 42);
        assert(pool.available() == 1);
    }
    assert(pool.available() == 2);
    {
        auto ptr = pool.acquire();
        assert(ptr && *ptr == 42);
        assert(pool.available() == 1);
        ptr.recycle();
        assert(not ptr);
        assert(pool.available() == 2);
    }
    assert(pool.available() == 2);
    {
        auto ptr = pool.acquire();
        assert(ptr && *ptr == 42);
        assert(pool.available() == 1);
        pool.recycle(ptr);
        assert(not ptr);
        assert(pool.available() == 2);
    }
    assert(pool.available() == 2);

    {
        auto ptr1 = pool.acquire();
        assert(ptr1);
        auto ptr2 = pool.acquire();
        assert(ptr2);
        assert(pool.empty());
        auto ptr3 = pool.acquire();
        assert(not ptr3);
    }

    return 0;
}

Posted in C++ | Tagged: , , , , , | Leave a Comment »