The boost pool library provides STL allocators that are more efficient when allocating objects of the same type (as opposed to std::allocator
which simply uses new
and delete
). This is what Stroustrup or Alexandrescu would call a small-object allocator.
As any custom allocator class, it works with essentially four separate functions: allocate, deallocate, construct, and destroy. I think their names are self-explanatory (unless you are confused about allocation vs. construction). To obtain a new object from the pool, you first call allocate(1)
to get a pointer and then you call construct( ptr, value )
on that pointer ptr
to get it constructed as a copy of value
(or moved). And you do the reverse when you want the delete that object. These are the mechanism that all STL containers use under-the-hood to allocate-construct-destroy-deallocate their objects.
You shouldn't trust the wikipedia article that you referred to (and not in general either), it is very poorly phrased, uses very vague and inaccurate language, and takes somewhat narrow view on the object-pool pattern. And btw, quoting wikipedia is worthless, you don't who wrote it, have no reason to trust it, always go to the source.
The pattern described in the wiki (and especially in the source article) has a very different objective from what the boost pool allocators try to accomplish. As described in the wiki, the emphasis is on reusing the objects without really destroying them (e.g., a thread-pool is a good example because it would be expensive to create and destroy threads frequently, and the source article is interested in pooling database service providers for similar reasons). In boost pool allocators, the emphasis is on avoiding invoking the heap (freestore) to allocate many small objects, a task that the heap cannot perform very efficiently and will cause it to become fragmented. It maybe should have been called "small-object allocators" instead, to avoid any confusion.
how does the pool know when a block of memory acquired by a client has been released back into the pool and is reusable if its interface hands back a direct pointer to element_type, yet a call to free() is still not required?
I don't think that it can. I believe that the story goes like this. You can choose to just allocate a bunch of objects from the pool, without ever deallocating them, and that is still safe in the sense that when you destroy the pool-allocator, all its memory is flushed with it, including all the objects that you left lingering in the pool. That's what they mean by "it is not required to free the objects", simply that your application will not leak memory beyond the life-time of the pool-allocator object if you forget to free all the objects from the pool.
But, if you don't tell the pool-allocator to deallocate the objects that you no longer need (and thus, can be reused) it will not be able to reuse those memory slots, that's just impossible (given that the allocators don't deliver any kind of special smart-pointer that would be able to track the allocated objects).
How can the boost pool re-use this memory if it cannot be certain that the memory is not still in use?
If it cannot be certain that the memory is not still in use, then there is no way that it can re-use the memory. Any piece of code that would make such a reckless thing as to "assume that an object is no longer needed without being sure" would be a worthless piece of code as it would obviously have undefined behavior and no programmer could possibly use it, ever.
And if it does not re-use this memory, is this even considered the same pattern as the one explained by the wiki reference?
No, it does not implement what is explained in the wiki. You'll have to get used to the fact that terminology sometimes clash in unfortunate ways. It is more common to refer to what boost pool implements either as a "memory pool" or as a "small object allocator". This is a structure optimized for somewhat small objects that are fairly cheap to construct and to copy. Because the heap (freestore) is tailored for larger blocks of memory and tends to deal poorly with trying to find a place for small objects, using it for that purpose is not a great idea, and can lead to heap fragmentation. So, pool-allocators essentially replace the heap with something that is more efficient at allocating many small objects of the same type. It doesn't re-use objects, but it can re-use memory that has been freed, just like the heap does. And it generally allocates its memory (that it allocates away) from the heap as a large contiguous block (e.g., with std::vector
). There are many other performance benefits to using a small-object allocator when appropriate. But what boost pool implements is in fact very different from what is described in the wiki. Here is the implementer's description of what pool-allocators are good for:
A good place to use a Pool is in situations where many (noncontiguous) small objects may be allocated on the heap, or if allocation and deallocation of the same-sized objects happens repeatedly.