template < typename T > class vtr public: vtr() : elements(0), size(0), max(0) { } void push_back(const T & v) if size >= max, grow() assert(size <= max) elements[size++] = v private: T * elements size_t size, max void grow() max = (max == 0 ? 1 : max*2) T * const ne = new T [max] for size_t i = 0; i < size; i++ ne[i] = elements[i] delete [] elements elements = ne
grow()
is expensive.
void grow() max = (max == 0 ? 1 : max*2) T * const ne = new T [max] for size_t i = 0; i < size; i++ ne[i] = elements[i] delete [] elements elements = ne
new
allocates and initializes new elements.
memcpy()
Optimizationfor size_t i = 0; i < size; i++ ne[i] = elements[i]
with
memcpy(ne, elements, sizeof(T)*size)
new
overhead.
memcpy()
violates the Rule of Three in so many ways.
void grow() max = (max == 0 ? 1 : max*2) T * const ne = static_cast<T *>(malloc(sizeof(T)*max)) memcpy(ne, elements, sizeof(T)*size) free(elements) elements = ne
push_back()
is now broken.
~vtr
is broken for the same reason.
memcpy()
still subverts the Rule of Three.
template < typename ElementT, class Allocator = allocator<ElementT> > class vector; template < typename CharT, class Traits = char_traits<CharT>, class Allocator = allocator<CharT> > class basic_string; typename basic_string<char> string;
delete
on malloc()
ed storage.
free()
on new
ed storage.
new
and delete
new
is responsible for allocation and
initialization.
new
is complicated and confusing.
delete
is responsible for clean-up and deallocation.
std::allocator<T>
class is an abstraction for
storage-management policies.
<memory>
header of the standard library.
template < typename T > class allocator { public: T * allocator(size_t); void deallocate(T *, size_t); void construct(T *, const T &); void destroy(T *); // Lots o' other stuff. }
allocator(i)
allocates enough uninitialized storage for i
elements of type T
.
sizeof(T)*i
.
deallocate(p, i)
frees the storage pointed to by p
for i
elements of type T
.
construct(p, v)
uses the T
value v
to initialized the
storage pointed to by p
.
destroy(p)
calls T
's destructor on the storage pointed to by
p
.
template <typename T> class avtr public: ~avtr() { uncreate() } private: std::allocator<T> alloc void grow() max_size = max(max_size*2, ptrdiff_t(1)) T * ne = alloc.allocator(max_size) uninitialized_copy(data, data + size, ne) uncreate() data = ne void uncreate() for i = data + size - 1; i != data; i-- alloc.destroy(i) alloc.deallocate(data, size)
uninitialized_copy(b, e, n)
copies the values in (b, e)
to
the uninitialized storage pointed to by n
.
T
's copy constructor with *b
as a parameter.
<memory>
.
See the complete code.
This page last modified on 19 December 2003.