C++ object pool that returns a smart pointer on request
unique_ptr ownership / lifetime issues:
Normally, std::unique_ptr indicates single ownership of an object and thus gives the user certain expectations of how they can safely use it. But here the object_pool &quot;owns&quot; the object (or at least the underlying memory), so the use of unique_ptr is rather misleading. Consider the following code:
{
    auto ptr = std::unique_ptr&lt;int, std::function&lt;void(int*)&gt;&gt;();

    {
        object_pool&lt;int&gt; pool;
        ptr = pool.request(5);
    }

    // uh oh...
}

We would normally expect the above code to work without problems. However, the custom unique_ptr deleter will attempt to call _object_pool.push_back(object) on a pool that doesn't exist any more.
At the very least, I'd suggest &quot;hiding&quot; the use of unique_ptr behind a typedef, and documenting thoroughly that it must go out of scope before the object pool:
template&lt;class T&gt;
using object_pool_ptr = std::unique_ptr&lt;T, std::function&lt;void(T*)&gt;&gt;;

This also means the user doesn't have to worry about typing out the custom deleter signature.
It would be even better to make object_pool_ptr a wrapper class around the unique_ptr to hide it completely.

object_pool destructor:
As a debugging feature, the object_pool could keep track of the total number of objects allocated. We could then check that our &quot;free list&quot; (the _object_pool deque) is the correct size in the object_pool destructor, rather than waiting until a pointer goes out of scope.
I don't think it's necessary to call pop_front() on individual elements in the destructor. We could call clear() after the loop, or allow the _object_pool to clean up naturally in its own destructor.

[Note: below this point are just possible things that might be useful, depending on what other features your object pool needs, and what you're actually using it for].

tracking allocated memory inside the pool:
This &quot;object pool is a free-list&quot; strategy is really clever... but maybe there are advantages to keeping track of all the allocated memory inside the object pool too?
We could use a std::deque&lt;std::aligned_storage_t&lt;sizeof(T)&gt;&gt; member variable allowing us to call push_back to add more elements without invalidating references (and hence pointers) to the original elements.
This also means we avoid the need to call global operators new and delete for every element.

manual lifetime (but not memory) management:
If the object pool keeps track of all allocated memory as above, perhaps it's ok to give the user a simple raw pointer to an allocated object and expect them to call an object_pool.destroy(ptr); function when they're done with it?
This isn't dangerous in terms of object lifetimes, since the object pool can still call the object destructors when necessary (and maybe issue a warning or assert() if desired). Although it would open up the possibility of pointers to destroyed objects being accidentally reused.
It also allows us to make the object_pool moveable, and add a clear() function.