Allocator and placement new

Asked

Viewed 85 times

0

I have a problem with placement new along with a "homemade allocator". The problem is that for data types (int) it works well, now for double, they start to trim very strange outputs. The classes:

   #include <cstdlib>

template<class T> class my_allocator {
public:
    T* allocate(size_t n);
    void deallocate(T* p, size_t n);
    void construct(T* p, const T& v);
    void destroy(T* p);


};

template<class T>
T* my_allocator<T>::allocate(size_t n)
{
    return (T*) malloc(n);
}

template<class T>
void my_allocator<T>::destroy(T* p)
{
    if( p )
        p->~T();
}

template<class T>
void my_allocator<T>::construct(T* p, const T& v)
{
    char* z = (char*) p;
    char* q = (char*) &v;
    for( int i = 0; i < sizeof(p); ++i )
        z[i] = q[i];
}

template<class T>
void my_allocator<T>::deallocate(T* p, size_t n)
{
    for( int i = 0; i < n; ++i )
        free(p);
}



#include "my_allocator.h"
#include <iostream>
using namespace std;

template<class T, class A = my_allocator<T> > class vector2 {
    A alloc;
    T* elem;

    int sz;
    int space;

public:
    vector2(): sz(0), space(0) { }
    explicit vector2(int s);

    vector2(const vector2&);
    vector2& operator=(const vector2&);

    ~vector2() { delete[] elem; }

    T& operator[](int n) { return elem[n]; }
    const T& operator[](int n) const { return elem[n]; }

    int size() const { return sz; }
    int capacity() const { return space; }

    void copy(const vector2& arg);

    void resize(int newsize, T val = T());
    void push_back(const T& d);
    void reserve(int newalloc);

};

template<class T>
void* operator new[](size_t n, my_allocator<T>& d)
{
    return d.allocate(n);
}

template<class T, class A>
void vector2<T, A>::reserve(int newalloc)
{
    if( newalloc <= space )
        return;
     T* p = new (alloc) T[newalloc];

    for( int i = 0; i < sz; ++i )
        alloc.construct(&p[i], elem[i]);

    for( int i = 0; i < sz; ++i )
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem, space);
    elem = p;
    space = newalloc;
}

template<class T, class A>
void vector2<T, A>::push_back(const T& val)
{
    if( !space )
        reserve(8);
    else if( sz == space )
        reserve(2*space);
    alloc.construct(&elem[sz], val);
    ++sz;
}

I am using "placement new correctly"?

3 answers

2

2

To your allocator be valid, it must behave in a manner equivalent to std::allocator. I see some problems with your:


T* my_allocator<T>::allocate(size_t n)

Here the documentation of std::allocator::allocate says:

Aloca n * sizeof(T) bytes of storage not initialized

However your code allocates only n bytes. Change to:

template<class T>
T* my_allocator<T>::allocate(size_t n)
{
    return (T*) malloc(n * sizeof(T));
}

void my_allocator<T>::construct(T* p, const T& v)

Documentation of std::allocator::construct says:

Builds an object of the type in T not initialized storage pointed by p

The important thing here is constrói. You are copying byte by byte, but not all types can be trivially constructed like this. However all types can be built using their builders. Here do the following:

template<class T>
void my_allocator<T>::construct(T* p, const T& v)
{
    new (p) T(v);
}

Here the function of this new is not to allocate memory. It builds an object in memory pointed by p using the constructor that picks up v argument (the copy constructor).

  • Thank you very much William!

  • 1

    Good, the original Construct() would work with int and double, but would cause a problem with any more elaborate type (with pointer members or member-references).

2

In addition to what has already been said, deallocatealso has problem, should be made only one free. The parameter n is the number of elements that has been allocated, but as you make the allocation of all of them in just one memory block, the misallocation should also be unique.

  • I didn’t even notice. Good eyes!

  • As you had already contributed I forced myself to do a fine reading, and I realized this, @Guilhermebernal.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.