Simple C++ object pool I am studying computer science and just for the sake of practise I thought of implementing an object pool.

This is my first implementation, it is simple and works correctly, but I would love any thoughts on it. Currently, the memory is allocated on the stack, but I am thinking of using policy based design to allow heap allocation as well.

Here is the code of the pool:

#include &lt;iostream&gt;
#include &lt;memory&gt;
#include &lt;functional&gt;

/**
 * Generic class for object pools.
 */
template &lt;class T, int SZ, class Initialiser, class Releaser&gt; class StackObjectPool {
public:
    using pointer = std::unique_ptr&lt;T,std::function&lt;void(T*)&gt; &gt;;
    using PoolType = StackObjectPool&lt;T,SZ,Initialiser, Releaser&gt;;

    StackObjectPool() {}
    StackObjectPool(const PoolType&amp; orig) = delete;
    ~StackObjectPool() {}

    /**
     * Acquires an object not being currently used
     * @return pointer to the acquired object
     * @throw std::out_of_range if all the objects inside the pool are being used
     */
    pointer acquire() {
        unsigned int index = 0; // look for the first free object
        while(m_occupied_registry[index]) ++index;
        if(index &gt;= SZ) throw std::out_of_range("Pool exceeded its size");
        m_occupied_registry[index] = true; // mark it as currently in use
        m_initialiser(&amp;m_objects[index]); // initialise it

        //return an unique_ptr that calls release when reset
        return pointer(&amp;m_objects[index], [this](T* element)-&gt;void{release(element);});
    }

    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; ostream, const PoolType&amp; pool) {
        for(unsigned int index = 0; index &lt; SZ; ++index) {
            std::cout&lt;&lt;(pool.m_occupied_registry[index]?"[occupied] ":"[free]\n");
            if(pool.m_occupied_registry[index]) {
                std::cout&lt;&lt;pool.m_objects[index]&lt;&lt;"\n";
            }
        }
        return ostream;
    }
private:

    void release(T* element) {
        unsigned int index = 0;
        while(&amp;m_objects[index] != element) ++index;
        m_occupied_registry[index] = false; // mark the released element as free
        m_releaser(element); // call release functor
    }

    Initialiser m_initialiser;
    Releaser m_releaser;
    bool m_occupied_registry[SZ] {0};
    T m_objects[SZ];
};


And here is a Test class and a simple main which I have used to test the pool:

class Test {
public:
    Test():m_a(0),m_b('0'){
        std::cout&lt;&lt;"Construct default Test"&lt;&lt;*this&lt;&lt;"\n";
    }
    Test(int a, char b): m_a(a), m_b(b) { 
        std::cout&lt;&lt;"Construct Test"&lt;&lt;*this&lt;&lt;"\n";
    }
    Test(const Test&amp; orig): m_a(orig.m_a),m_b(orig.m_b) {
        std::cout&lt;&lt;"Construct cpy Test"&lt;&lt;*this&lt;&lt;"\n";
    }
    ~Test() {
        std::cout&lt;&lt;"Delete Test"&lt;&lt;*this&lt;&lt;"\n";
    }
    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; ostream, const Test&amp; test) {
        ostream&lt;&lt;"["&lt;&lt;test.m_a&lt;&lt;",'"&lt;&lt;test.m_b&lt;&lt;"']";
        return ostream;
    }
private:
    int m_a;
    char m_b;
};

struct Initialiser {
    void operator() (Test* element) {
        std::cout&lt;&lt;"Initialising Test"&lt;&lt;*element&lt;&lt;"\n";
    }
};

struct Releaser {
    void operator() (Test* element) {
        std::cout&lt;&lt;"Releasing Test"&lt;&lt;*element&lt;&lt;"\n";
    }
};

int main(int argc, char** argv) {
    using TestPool = StackObjectPool&lt;Test,5, Initialiser, Releaser&gt;;
    TestPool pool;
    TestPool::pointer pt1, pt2,pt3,pt4,pt5;

    std::cout&lt;&lt;pool;

    pt1= pool.acquire();
    std::cout&lt;&lt;"Aquired pt:"&lt;&lt;*pt1&lt;&lt;"\n";
    //pt1.reset();

    std::cout&lt;&lt;pool;

    pt2 = pool.acquire();
    std::cout&lt;&lt;"Aquired pt:"&lt;&lt;*pt2&lt;&lt;"\n";
    pt2.reset();

    std::cout&lt;&lt;pool;

    pt3 = pool.acquire();
    std::cout&lt;&lt;"Aquired pt:"&lt;&lt;*pt3&lt;&lt;"\n";
    //pt3.reset();

    std::cout&lt;&lt;pool;
    return 0;
}
You might change:

void release(T* element, unsigned int index) {
    if (&amp;m_objects[index] != element) {
            std::cerr &lt;&lt; "no match index and element\n";
            return; // or exit(1);
    }
    m_occupied_registry[index] = false; // mark the released element as free
    m_releaser(element); // call release functor
}


and at the acquire  change the return line:

    return pointer(&amp;m_objects[index], [this,index](T* element)-&gt;void{release(element,index);});


The above will improve the efficiency of the release operation, as you don't need to search for the element.