The <
m
emor
y
>
header declares types and functions for allocating and using memory.
The auto_ptr
class template provides a simple ownership model for working with pointers. It can be extremely useful for writing exception-safe code.
Several functions work with uninitialized memory, which can be helpful when implementing a container. For example, an implementation of vector must allocate an uninitialized array of objects, and initialize elements of the array as they are needed. The uninitialized_
... functions canc ome in handy.
The allocator
class template is used by all the standard containers.
Encapsulate 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
. If you want to write your own container, or provide a custom allocator for the standard containers, though, you should take the time to understand allocator
.
The standard library requires all instances of an allocator for a given type to be equivalent. For example, if you have two lists of integers, each list object has its own allocator object. The two allocator objects are interchangeable and objects allocated with one allocator can be freed with the other.
// Create two distinct allocator objects. std::allocator<int> a, b; // Assign allocator objects to lists x and y. std::list<int> x(a), y(b); // allocators are equivalent: assert(a == b); // but not identical: assert(&a != &b); // Objects in one list interchangeable with other list. swap(x, y);
Perhaps the easiest way to understand allocator
is to take a look at a trivial implementation, in Example 13-33. Note that a library might have a more complicated implementation, to handle multithreading, improve performance, etc. This particular implementation is just a sample.
Example 13-33: Sample allocator implementation.
template<typename T> class myallocator { 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 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; }; };
Following are the members of allocator
:
allocator
() throw()
allocator
(const allocator&) throw()
template<class
U>
allocator
(const
allocator<U>&)
throw()
pointer
address
(
r
eference x) const
const_pointer
address
(const_reference x) const
address
function returns the address of x
, that is, &x
.pointer
allocate
(size_type
n,
allocator<void>::const_pointer hint = 0)
allocate
function 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 yet 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.hint
to improve performance.typedef const T*
const_pointer
const_pointer
type must be const
T*
. The standard containers are free to assume that const_
p
ointer
is the same as const
T*
, even for a custom allocator.typedef const T&
const_reference
const_reference
type must be const
T&
. The standard containers are free to assume that cons
t
_reference
is the same as const
T&
, even for a custom allocator.void
construct
(pointer p, const T& val)
new
operator to construct an instance of T
having value val
, and using the memory that p
points to. That is, it calls new(static_cast<void*>(p))
T(val)
.
deallocate
(pointer p, size_type n)deallocate
function 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
.
destroy
(pointer p)destroy
function calls the destructor for the object at address p
. That is, it calls reinterpret_cast<T*>(p)->~T()
.typedef
ptrdiff_t
difference_type
difference_type
type represents the difference of two pointers. It must be ptrdiff_t
, even in a custom allocator class.size_type
max_size
()
const
throw()
max_size
function returns the maximum size that can be passed to allocate
.typedef T*
pointer
pointer
type must be T*
. The standard containers are free to assume that p
ointer
is the same as T*
, even for a custom allocator.template <class U> struct
rebind
rebind
class has a single typedef, other
, which rebinds the allocator to a new value type.typedef T&
reference
reference
type must be T&
. The standard containers are free to assume that reference
is the same as T&
, even for a custom allocator.typedef size_t
size_
t
ype
size_type
type must be size_t
, even in a custom allocator.typedef T
value_
t
ype
value_type
must be T
, even in a custom allocator.allocator<void> class, new operator, delete keyword, <new>
Specialize allocator for void pointers
template <> class allocator<void> { public: typedef void* pointer; typedef const void* const_pointer; typedef void value_type; template <class U> struct rebind { typedef allocator<U> other; }; };
The allocator<void>
specialization is necessary to represent pointers to void
without permitting the allocation of objects of type void
.
allocator class template
Smart pointer to manage ownership of pointers
template <class T> struct auto_ptr_ref {}; template<class T> class auto_ptr { public: typedef T element_type; explicit auto_ptr(T* p = 0) throw(); auto_ptr(auto_ptr&) throw(); template<class U> auto_ptr(auto_ptr<U>&) throw(); auto_ptr(auto_ptr_ref<T>) throw(); ~auto_ptr() throw(); auto_ptr& operator=(auto_ptr&) throw(); template<class U> auto_ptr& operator=(auto_ptr<U>&) throw(); auto_ptr& operator=(auto_ptr_ref<T> r) throw(); T& operator*() const throw(); T* operator->() const throw(); T* get() const throw(); T* release() throw(); void reset(T* p = 0) throw(); template<class U> operator auto_ptr_ref<U>() throw(); template<class U> operator auto_ptr<U>() throw(); };
The auto_ptr
class template implements a smart pointer for ownership of pointers. Proper use of auto_ptr
ensures that a pointer has exactly one owner (which prevents accidental double deletes), and the owner automatically frees the memory when the owner goes out of scope (which prevents memory leaks). Assignment of auto_ptr
values transfers ownership from the source to the target of the assignment.
The aut
o
_ptr_
r
ef
type holds a reference to an auto_ptr
. Implicit conversions between auto_ptr
and aut
o
_ptr_ref
facilitate returning auto_ptr
objects from functions. The details of auto_ptr_ref
are implementation-defined.
Some of the typical uses for auto_ptr
are as follows:
auto_
p
tr
, which ensures the memory is properly freed when the owning object is destroyed.auto_ptr
variable. When the function returns (normally or as the result of an exception), the object is destroyed automatically. This can drastically reduce the need for try-catch statements.auto_ptr
, you can safely ensure that each object has exactly one owner, and ownership is properly passed via assignment and function calls. When the object is no longer needed, it is freed automatically.On the flip side, because you cannot simply copy or assign an auto_ptr
, you cannot use auto_ptr
objects in any standard container. Another limitation is that auto_ptr
cannot hold a pointer to an array. Allocating and freeing a single object (e.g., new
int
) is different from allocating and freeing an array of objects, (e.g., new
int[42]
), and auto_ptr
is designed to work only with single objects.
A useful guideline is that a program should never have bare pointers, e.g., int*
x
. Bare pointers are error-prone: subject to memory leaks, double-freeing, and dangling references. Instead, use some form of ownership, such as auto_ptr<>
, or one of the Boost smart pointers.
The Boost project has additional smart pointer class templates that permit copying, arrays, and shared owneship. See Appendix ### for more information about Boost.
Example 13-34 shows some uses of auto_ptr
.
Example 13-34: Sample uses for auto_ptr.
class DisplayContext { // Display or graphics context for drawing on a window. public: DisplayContext() : brush_(new brush), pen_(new pen) {...} ... private: // Automatically manage lifetime of the pen and brush. // When the DisplayContext is freed, so are the pen // and brush instances. std::auto_ptr<brush> brush_; std::auto_ptr<pen> pen_; }; void repaint() { // Allocate a new display context. Use auto_ptr to ensure // it will be freed automatically. std::auto_ptr<DisplayContext> dc(new DisplayContext()); // Draw stuff on the display context. dc->draw(...); // No need to call release; the display context is // automatically released when repaint() returns. }
Following are the members of auto_ptr
:
auto_ptr
(T* p = 0) throw()auto_ptr
object to own the pointer p
.
auto_ptr
(auto_ptr& x) throw()
auto_ptr
(auto_ptr<U>& x) throw()auto_ptr
object with the pointer returned from x.
r
elease()
. In the second version, the type U*
must be implicitly convertible to T*
. Note that x
is not const
. It is not possible to copy a const
auto_ptr
because to do so would break the ownership rules.
auto_ptr
(auto_ptr_ref<T> r) throw()
aut
o
_
p
tr
object with the pointer obtained from calling release
on r
's auto_ptr
.
~auto_ptr
()
throw()
delete get()
.T*
get
()
const
throw()
get
function returns the owned pointer.T*
release
()
throw()
release
function returns get()
and resets the owned pointer to 0
.void
reset
(T* p = 0)
throw()
reset
function deletes the owned pointer (if it is not equal to p
) and saves p
as the new owned pointer.template<class U>
operator
auto_ptr_ref<U
>
()
throw()
auto_ptr_ref
conversion operator returns an auto_ptr_
r
ef
object that contains *
t
his
. Thus, ownership of the pointer is transferred to the returned auto_ptr_ref
.template<class U>
operator
auto_ptr<U
>
()
throw()
auto_ptr
conversion operator calls release()
and returns a new auto_ptr
that has ownership of the pointer, which must be implicitly convertible to U*
.auto_ptr&
operato
r
=
(auto_ptr& x)
throw()
template<class U>
auto_ptr&
operato
r
=
(auto_ptr<U>& x)
throw()
auto_ptr&
operato
r
=
(auto_ptr_ref<T>
r)
throw()
x
or by the auto_ptr
object held by r
to *
t
his
. That is, it calls reset(x.release())
.T&
operator
*
()
const
throw()
*
g
et()
.T*
operator
->
()
const
throw()
get()
.new operator
Allocate temporary memory buffer
template <class T> pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n);
The ge
t
_temporary_
b
uffer
function template allocates memory for temporary use. The request is for up to n
adjacent objects of type T
. The return value is a pair
of the pointer to the newly allocated memory and the actual size of the memory allocated (in units of sizeof(T)
). If the memory cannot be allocated, the return value is a pair of 0 and 0. The allocated memory must be freed by calling retu
rn
_temporary_
b
uffer
. The temporary buffer is uninitialized.
This function has limited usefulness. You must test the return value to see how much memory was allocated, and you must ensure the memory is properly freed if an exception is raised. It is usually simpler to call new
and save the pointer in an au
to
_ptr<>
.
auto_ptr class template, return_temporary_buffer function template, pair in <utility>
Iterator for uninitialized memory
template <class OutputIterator, class T> class raw_storage_iterator : public iterator<output_iterator_tag,void,void,void,void> { public: explicit raw_storage_iterator(OutputIterator x); raw_storage_iterator<OutputIterator,T>& operator*(); raw_storage_iterator<OutputIterator,T>& operator=(const T& element); raw_storage_iterator<OutputIterator,T>& operator++(); raw_storage_iterator<OutputIterator,T> operator++(int); };
The raw_storage_
it
erator
class template implements an output iterator that writes to uninitialized memory. It adapts another output iterator that must have operat
or
&
return a pointer to T
. A typical use is for the adapted iterator to be a pointer to uninitialized memory.
Use the raw_storage_
i
terator
as you would any other output iterator.
uninitialized_copy function template, uninitialized_fill function template, uninitialized_fill_n function template, <iterator>
Free temporary memory buffer
template <class T> void return_temporary_buffer(T* p);
The return_temporary_
b
uffer
function reclaims the memory that was previously allocated by get_temporary_buffer
.
get_temporary_buffer function template
Copy into uninitialized memory
template <class InputIter, class FwdIter> FwdIter uninitialized_copy(InputIter first, InputIter last, FwdIter result);
The uninitialized_copy
function template is like the copy
algorithm, except the result
iterator is assumed to point to uninitialized memory. The range [first
, last
) is copied to result
using placement new
.
raw_storage_iterator class template, uninitialized_fill function template, copy in <algorithm>, new operator
Fill uninitialized memory
template <class FwdIter, class T> void uninitialized_fill(FwdIter first, FwdIter last, const T& x);
The uninitialized_
f
ill
function template is like the fill
algorithm, except that it fills uninitialized memory. Every item in the range [first
, last
) is constructed as a copy of x
, using placement new
.
raw_storage_iterator class template, uninitialized_copy function template, uninitialized_fill_n function template, new operator
Fill uninitialized memory
template <class FwdIter, class Size, class T> void uninitialized_fill_n(FwdIter first, Size n, const T& x);
The uniniti
alized
_fill_n
function template is like the fil
l
_n
algorithm, except it fills uninitialized memory. Starting with first
, n
copies of x
are constructed using placement new
.
raw_storage_iterator class template, uninitialized_fill function template, new operator
Compare allocators for equality
template <class T1, class T2> bool operator==(const allocator<T1>&, const allocator<T2>&) throw();
The operator==
function template always returns true
. In other words, any object of type allocator
is considered to the same as every other allocator
. The standard library relies on this assumption.
allocator class template
Compare allocators for inequality
template <class T1, class T2> bool operator!=(const allocator<T1>&, const allocator<T2>&) throw();
The operator!=
function template always returns false
. In other words, any object of type allocator
is considered to the same as every other allocator
. The standard library relies on this assumption.
allocator class template