allocator class template — Encapsulates memory allocation and deallocation
template <class T> class allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template <class U> struct rebind { typedef allocator<U> other; }; allocator( ) throw( ); allocator(const allocator&) throw( ); template <class U> allocator(const allocator<U>&) throw( ); ~allocator( ) throw( ); pointer address(reference x) const; const_pointer address(const_reference x) const; pointer allocate(size_type, allocator<void>::const_pointer hint = 0); void deallocate(pointer p, size_type n); size_type max_size( ) const throw( ); void construct(pointer p, const T& val); void destroy(pointer p); };
The allocator
class
template encapsulates basic allocation and deallocation functions.
The standard containers rely on allocators for memory management and
use allocator
as the default
allocator.
Most programmers do not need to use allocator
, which offers few advantages
over plain new
and delete
. However, if you want to write your
own container, or provide a custom allocator for the standard
containers, you should take the time to understand allocator
.
Perhaps the easiest way to understand allocator
is to take a look at a trivial
implementation in Example
13-30. Note that a library might have a more complicated
implementation to handle multithreading, improve performance, etc.
Some libraries offer allocators for special purposes, such as
allocating memory that can be shared among multiple processes. This
particular implementation is just a sample.
Example 13-30. Sample allocator implementation
template<typename T> class myallocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template <class U> struct rebind { typedef myallocator<U> other; }; myallocator( ) throw( ) {} myallocator(const myallocator&) throw( ) {} template <class U> myallocator(const myallocator<U>&) throw( ) {} ~myallocator( ) throw( ) {} pointer address(reference x) const {return &x;} const_pointer address(const_reference x) const {return &x;} pointer allocate(size_type n, void* hint = 0) { return static_cast<T*>(::operator new (n * sizeof(T)) ); } void deallocate(pointer p, size_type n) { ::operator delete(static_cast<void*>(p)); } size_type max_size( ) const throw( ) { return std::numeric_limits<size_type>::max( ) / sizeof(T); } void construct(pointer p, const T& val) { new(static_cast<void*>(p)) T(val); } void destroy(pointer p) { p->~T( ); } }; template<typename T> bool operator==(const myallocator<T>&, const myallocator<T>&) { return true; } template<typename T> bool operator!=(const myallocator<T>&, const myallocator<T>&) { return false; } template<> class myallocator<void> { public: typedef void* pointer; typedef const void* const_pointer; typedef void value_type; template <class U> struct rebind { typedef myallocator<U> other; }; };
The following are the members of allocator
:
allocator
( ) throw( )
, allocator
(const allocator&) throw( )
, template<class
U>
allocator
(const
allocator<U>&)
throw( )
Constructs a new allocator object, possibly copying an existing allocator. Remember that all instances must be equivalent, so an allocator typically does not have any data members to initialize.
pointer
address
(reference x)
const
, const_pointer
address
(const_reference x)
const
Returns the address of x
, that is, &x
.
pointer
allocate
(size_type
n, allocator<void>::const_pointer
hint = 0)
Calls the global new
operator to allocate enough memory to hold n
objects of type T
. The hint
argument must be 0
or a pointer obtained from a prior
call to allocate
that has
not been passed to deallocate
. The return value is a
pointer to the newly allocated memory. If the memory cannot be
allocated, bad_alloc
is
thrown.
An implementation might use hint
to improve performance.
typedef const
T*
const_pointer
A type for a pointer to const
. In a custom allocator, the
type should be equivalent to const
T*
.
typedef const T&
const_reference
A type for a const
lvalue. In a custom allocator, the type should be equivalent
to const
T&
.
void
construct
(pointer p, const T&
val)
Calls the global new
operator to construct an instance of T
with value val
using the memory that p
points to. That is, it calls
new(static_cast<void*>(p))
T(val)
.
void
deallocate
(pointer p, size_type
n)
Calls the global delete
operator to free the memory
that p
points to. The
n
argument is the number of
items of type T
—the same
value passed to allocate
.
void
destroy
(pointer
p)
Calls the destructor for the object at address p
. That is, it calls reinterpret_cast<T*>(p)->~T(
)
.
typedef
ptrdiff_t
difference_type
A type that represents the difference of any two
pointers that the allocator returns from allocate( )
.
size_type
max_size
( )
const
throw(
)
Returns the maximum size that can be passed to allocate
.
typedef T*
pointer
A pointer type. In a custom allocator, the type should
be equivalent to T*
.
template <class U>
struct
rebind
Binds the allocator object to a different value type.
The rebind
class has a
single typedef, other
,
which is an instance of the same allocator template, but with
U
as the template
parameter. The rebind
template is necessary for standard containers that allocate
helper objects, such as link nodes, rather than allocating
values directly. If you are not implementing a standard
container, you probably don't need to understand rebind
.
typedef T&
reference
An lvalue type. In a custom allocator, the type should
be equivalent to T&
.
typedef size_t
size_type
A type that can represent the size of the largest allocation request.
typedef T
value_type
The type of allocated values, which is typically
T
.