Search code examples
c++memory-managementmallocfreeallocator

Implementing simple allocator


As a part of vector implementation I have to implement an allocator using functions malloc() and free() given the below interface:

class Allocator manages memory for class vector:

template<class T>
class Allocator {
public:
    // function members
    T* allocate(int n);
    void deallocate(T* p, int n);

    void construct(T* p, const T& v);
    void destroy(T* p);
};

class Allocator member implementations:

/*
    Function: allocate()
    Use: allocator_object.allocator(num_of_elements) 

    Implicit in vector_base constructor.
    It wraps malloc(); Throws bad_alloc
    if allocation unsuccessful.
*/
template <class T>
T* Allocator<T>::allocate(int n) {
    try {
        std::auto_ptr<T> mem_ptr = reinterpret_cast<T*>(malloc(n * sizeof(T)));
    } catch (std::bad_alloc& e) {
        std::cerr <<"bad_alloc caught: "<< e.what() <<'\n';
        throw;
    }
    return mem_ptr.release();
}

/*
    Function: deallocate()
    Use: allocator_object.deallocate(mem_ptr, redundant_par);

    Implicit in base_vector destructor.
    It returns memory to free store. 
    First argument is the pointer returned by malloc(). 
*/
template <class T>
void Allocator<T>::deallocate(T* mem_ptr, int n) {
    free(mem_ptr);
}

/*
    Function: construct()
    Use: allocator_object.construct(elem_ptr[i], value)

    Implicit in vector_base constructor
    and all modifying members of vector.
    It assigns the value passed as second
    argument to the element with address
    held by the pointer passed as a first 
    argument.
*/
template <class T>
void Allocator<T>::construct(T* p, const T& v = T()) {
    *p = v;
}

/*
    Function: destroy()
    Use: allocator_object.destroy(elem_ptr[i]); 

    Implicitly in vector members: reserve(), resize();
    It assigns type default value to the element
    with address held by the pointer passed as argument.
*/
template <class T>
void Allocator<T>::destroy(T* p) {
    *p = T(); // ? not sure if right 
} 

How to check for possible bad allocations from malloc() in function allocate()1, is the current method correct?

Edit:

Is the implementation of function destroy() correct2, could you give me an example of correct implementation?

There is an additional argument, n, in function deallocate() which I can't figure out how(what for) to use.


1. I know I'm using a deprecated std::auto_ptr, just following the book recommendations wrongly trying to get rid of the pointer in case of bad allocation.

2. I've read the documentation for function destroy(), but considering the fact that the allocated memory is one contiguous chunk that is free()d by passing the pointer returned by malloc(), the only reasonable object destruction is the assignment of a default value.


Solution

  • std::bad_alloc isn't magically generated. malloc fails by returning nullptr and there's nothing which would convert that into an exception. You call malloc, so you must check the return value manually.

    destroy is wrong for the same reason as construct is wrong: They're a pair of functions that turn raw memory into an object and back. The normal way to do so is by placement new and direct invocation of the destructor. You're just calling the assignment operator there, which doesn't affect the objects lifetime at all.