...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
There are several interfaces provided which allow users great flexibility in how they want to use Pools. Review the concepts document to get the basic understanding of how the various pools work.
Object Usage is the method where each Pool is an object that may be created and destroyed. Destroying a Pool implicitly frees all chunks that have been allocated from it.
Singleton Usage is the method where each Pool is an object with static duration; that is, it will not be destroyed until program exit. Pool objects with Singleton Usage may be shared; thus, Singleton Usage implies thread-safety as well. System memory allocated by Pool objects with Singleton Usage may be freed through release_memory or purge_memory.
Some Pool interfaces throw exceptions when out-of-memory; others will return 0
. In
general, unless mandated by the Standard, Pool interfaces will always prefer
to return 0
instead of throwing an exception.
An ordered pool maintains it's free list in order of the address of each free block - this is the most efficient way if you're likely to allocate arrays of objects. However, freeing an object can be O(N) in the number of currently free blocks which can be prohibitively expensive in some situations.
An unordered pool does not maintain it's free list in any particular order, as a result allocation and freeing single objects is very fast, but allocating arrays may be slow (and in particular the pool may not be aware that it contains enough free memory for the allocation request, and unnecessarily allocate more memory).
The pool
interface is a simple
Object Usage interface with Null Return.
pool
is a fast memory allocator,
and guarantees proper alignment of all allocated chunks.
pool.hpp
provides
two UserAllocator
classes and a template class pool
,
which extends and generalizes the framework provided by the Simple
Segregated Storage solution. For information on other pool-based
interfaces, see the other Pool
Interfaces.
Synopsis
There are two UserAllocator
classes provided. Both of them are in pool.hpp
.
The default value for the template parameter UserAllocator
is always default_user_allocator_new_delete
.
struct default_user_allocator_new_delete { typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; static char * malloc(const size_type bytes) { return new (std::nothrow) char[bytes]; } static void free(char * const block) { delete [] block; } }; struct default_user_allocator_malloc_free { typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; static char * malloc(const size_type bytes) { return reinterpret_cast<char *>(std::malloc(bytes)); } static void free(char * const block) { std::free(block); } }; template <typename UserAllocator = default_user_allocator_new_delete> class pool { private: pool(const pool &); void operator=(const pool &); public: typedef UserAllocator user_allocator; typedef typename UserAllocator::size_type size_type; typedef typename UserAllocator::difference_type difference_type; explicit pool(size_type requested_size); ~pool(); bool release_memory(); bool purge_memory(); bool is_from(void * chunk) const; size_type get_requested_size() const; void * malloc(); void * ordered_malloc(); void * ordered_malloc(size_type n); void free(void * chunk); void ordered_free(void * chunk); void free(void * chunks, size_type n); void ordered_free(void * chunks, size_type n); };
Example:
void func() { boost::pool<> p(sizeof(int)); for (int i = 0; i < 10000; ++i) { int * const t = p.malloc(); ... // Do something with t; don't take the time to free() it. } } // on function exit, p is destroyed, and all malloc()'ed ints are implicitly freed.
The template class object_pool
interface is an Object Usage interface with Null Return, but is aware
of the type of the object for which it is allocating chunks. On destruction,
any chunks that have been allocated from that object_pool
will have their destructors called.
object_pool.hpp
provides a template type that can be used for fast and efficient memory
allocation. It also provides automatic destruction of non-deallocated
objects.
For information on other pool-based interfaces, see the other Pool Interfaces.
Synopsis
template <typename ElementType, typename UserAllocator = default_user_allocator_new_delete> class object_pool { private: object_pool(const object_pool &); void operator=(const object_pool &); public: typedef ElementType element_type; typedef UserAllocator user_allocator; typedef typename pool<UserAllocator>::size_type size_type; typedef typename pool<UserAllocator>::difference_type difference_type; object_pool(); ~object_pool(); element_type * malloc(); void free(element_type * p); bool is_from(element_type * p) const; element_type * construct(); // other construct() functions void destroy(element_type * p); };
Template Parameters
ElementType
The template parameter is the type of object to allocate/deallocate. It must have a non-throwing destructor.
UserAllocator
Defines the method that the underlying Pool will use to allocate memory from the system. Default is default_user_allocator_new_delete. See __UserAllocator for details.
Example: struct X { ... }; // has destructor with side-effects.
void func() { boost::object_pool<X> p; for (int i = 0; i < 10000; ++i) { X * const t = p.malloc(); ... // Do something with t; don't take the time to free() it. } } // on function exit, p is destroyed, and all destructors for the X objects are called.
The singleton_pool interface
at singleton_pool.hpp
is a Singleton Usage interface with Null Return. It's just the same as
the pool interface but with Singleton Usage instead.
Synopsis
template <typename Tag, unsigned RequestedSize, typename UserAllocator = default_user_allocator_new_delete> struct singleton_pool { public: typedef Tag tag; typedef UserAllocator user_allocator; typedef typename pool<UserAllocator>::size_type size_type; typedef typename pool<UserAllocator>::difference_type difference_type; static const unsigned requested_size = RequestedSize; private: static pool<size_type> p; // exposition only! singleton_pool(); public: static bool is_from(void * ptr); static void * malloc(); static void * ordered_malloc(); static void * ordered_malloc(size_type n); static void free(void * ptr); static void ordered_free(void * ptr); static void free(void * ptr, std::size_t n); static void ordered_free(void * ptr, size_type n); static bool release_memory(); static bool purge_memory(); };
Notes
The underlying pool p
referenced by the static functions in singleton_pool
is actually declared in a way so that it is:
main()
begins and after main()
ends. All of the static functions
of singleton_pool synchronize their access to p
.
Note that a different underlying pool
p
exists for each different
set of template parameters, including implementation-specific ones.
Template Parameters
Tag
The Tag template parameter allows different unbounded sets of singleton pools to exist. For example, the pool allocators use two tag classes to ensure that the two different allocator types never share the same underlying singleton pool.
Tag is never actually used by singleton_pool
.
RequestedSize The requested size of memory chunks to allocate. This is passed as a constructor parameter to the underlying pool. Must be greater than 0.
UserAllocator
Defines the method that the underlying pool will use to allocate memory from the system. See User Allocators for details.
Example: struct MyPoolTag { };
typedef boost::singleton_pool<MyPoolTag, sizeof(int)> my_pool; void func() { for (int i = 0; i < 10000; ++i) { int * const t = my_pool::malloc(); ... // Do something with t; don't take the time to free() it. } // Explicitly free all malloc()'ed ints. my_pool::purge_memory(); }
The pool_allocator interface
is a Singleton Usage interface with Exceptions. It is built on the singleton_pool
interface, and provides a Standard Allocator-compliant class (for use
in containers, etc.).
Introduction
Provides two template types that can be used for fast and efficient memory allocation. These types both satisfy the Standard Allocator requirements [20.1.5] and the additional requirements in [20.1.5/4], so they can be used with Standard or user-supplied containers.
For information on other pool-based interfaces, see the other Pool Interfaces.
Synopsis
struct pool_allocator_tag { }; template <typename T, typename UserAllocator = default_user_allocator_new_delete> class pool_allocator { public: typedef UserAllocator user_allocator; typedef T value_type; typedef value_type * pointer; typedef const value_type * const_pointer; typedef value_type & reference; typedef const value_type & const_reference; typedef typename pool<UserAllocator>::size_type size_type; typedef typename pool<UserAllcoator>::difference_type difference_type; template <typename U> struct rebind { typedef pool_allocator<U, UserAllocator> other; }; public: pool_allocator(); pool_allocator(const pool_allocator &); // The following is not explicit, mimicking std::allocator [20.4.1] template <typename U> pool_allocator(const pool_allocator<U, UserAllocator> &); pool_allocator & operator=(const pool_allocator &); ~pool_allocator(); static pointer address(reference r); static const_pointer address(const_reference s); static size_type max_size(); static void construct(pointer ptr, const value_type & t); static void destroy(pointer ptr); bool operator==(const pool_allocator &) const; bool operator!=(const pool_allocator &) const; static pointer allocate(size_type n); static pointer allocate(size_type n, pointer); static void deallocate(pointer ptr, size_type n); }; struct fast_pool_allocator_tag { }; template <typename T typename UserAllocator = default_user_allocator_new_delete> class fast_pool_allocator { public: typedef UserAllocator user_allocator; typedef T value_type; typedef value_type * pointer; typedef const value_type * const_pointer; typedef value_type & reference; typedef const value_type & const_reference; typedef typename pool<UserAllocator>::size_type size_type; typedef typename pool<UserAllocator>::difference_type difference_type; template <typename U> struct rebind { typedef fast_pool_allocator<U, UserAllocator> other; }; public: fast_pool_allocator(); fast_pool_allocator(const fast_pool_allocator &); // The following is not explicit, mimicking std::allocator [20.4.1] template <typename U> fast_pool_allocator(const fast_pool_allocator<U, UserAllocator> &); fast_pool_allocator & operator=(const fast_pool_allocator &); ~fast_pool_allocator(); static pointer address(reference r); static const_pointer address(const_reference s); static size_type max_size(); static void construct(pointer ptr, const value_type & t); static void destroy(pointer ptr); bool operator==(const fast_pool_allocator &) const; bool operator!=(const fast_pool_allocator &) const; static pointer allocate(size_type n); static pointer allocate(size_type n, pointer); static void deallocate(pointer ptr, size_type n); static pointer allocate(); static void deallocate(pointer ptr); };
Template Parameters
T The first template parameter is the type of object to allocate/deallocate.
UserAllocator Defines the method that the underlying Pool will use to allocate memory from the system. See User Allocators for details.
Example:
void func() { std::vector<int, boost::pool_allocator<int> > v; for (int i = 0; i < 10000; ++i) v.push_back(13); } // Exiting the function does NOT free the system memory allocated by the pool allocator. // You must call // boost::singleton_pool<boost::pool_allocator_tag, sizeof(int)>::release_memory(); // in order to force freeing the system memory.