4.5 Allocators and memory handling

"One of the common problems in portability is to be able to encapsulate the information about the memory model.", [2], 7. This information includes the knowledge of


STL provides allocators which are objects that encapsulate the above information. As mentioned in section 4.1.1, all the STL containers are parametrized in terms of allocators. So, containers don't have any memory model information coded inherently but are provided with this information by taking an allocator object as argument.

The idea is that changing memory models is as simple as changing allocator objects. The allocator allocator, which is defined in defalloc.h, is used as default allocator object. The compiler vendors are expected to provide allocators for the memory models supported by their product. So, for Borland C++ allocators for different memory models are provided (see 3.2).

For every memory model there are corresponding allocate, deallocate, construct and destroy template functions defined. allocate returns a pointer of type T* to an allocated buffer, which is no less than n*sizeof(T).


template <class T>
inline T* allocate(ptrdiff_t size, T*);

deallocate frees the buffer allocated by allocate.


template <class T>
inline void deallocate(T* buffer);

construct puts results directly into uninitialized memory by calling the appropriate copy constructor.


template <class T1, class T2>
inline void construct(T1* p, const T2& value) {
   new (p) T1(value);
}

destroy calls the destructor for a specified pointer.


template <class T>
inline void destroy(T* pointer) {
   pointer->~T();
}

If you have a container of pointers to certain objects, the container destructor calls a special destroy function to call all the single pointer destructors and free the memory allocated. To make this work under Borland C++, a template specialization must be provided.


class my_int {
public:
   my_int (int i = 0) { ii = new int(i); }
  ~my_int () { delete ii; }private: int* ii;
};

// the following template specialization is necessary when using Borland C++
inline void destroy (my_int** pointer) { 
   (*pointer)->~my_int();
}

void main (void) {
   vector<my_int*> v (10); 
   for (int i = 0; i < 10; i++) { v[i] = new my_int(i); } 

// allocated my_int memory and vector v are destroyed at end of scope
}

When you use a container of pointers to objects which do not have an explicit destructor defined, a function like seq_delete can be implemented to free all the memory allocated.


template <class ForwardIterator>
inline void seq_delete (ForwardIterator first, ForwardIterator last) {
   while (first != last) delete *first++;
}
vector<char*> v;

char* c1 = new char[20]; strcpy (c1, "Tim");
char* c2 = new char[20]; strcpy (c2, "Charles");
v.push_back (c1); v.push_back (c2);

seq_delete (v.begin(), v.end() );

// vector v is destroyed at the end of scope

Continue with section 5

Back to index


Johannes Weidl (J.Weidl@infosys.tuwien.ac.at) - Apr 16, 1996