Allocator and placement new

0

I have a problem with placement new along with a "homemade allocator". The problem is that for data types (int) it works fine, now for double, very strange outputs start to appear. 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'm correctly using "placement new"?

    
asked by anonymous 07.02.2014 / 18:28

3 answers

2

In allocate (n), n is the number of elements, not the size in bytes. Malloc () should be n * sizeof (T). Deallocate () is already correct.

Source: link

    
07.02.2014 / 18:54
2

For your allocator to be valid, it must behave equivalent to std::allocator . I see some issues with your:

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

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

  

Allocates% of bytes of uninitialized storage

However, your code only allocates n * sizeof(T) bytes. Change to:

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

n

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

  

Constructs an object of type in std::allocator::construct in uninitialized storage pointed to by T

The important thing here is p . 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's how:

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

Here the function of this constrói is not to allocate memory. It constructs an object in memory pointed to by new using the constructor that takes p of argument (the copy constructor).

    
07.02.2014 / 18:54
2

In addition to what has already been said, deallocate also has a problem, only free should be done. The n parameter is the number of elements that has been allocated, but since you allocate all of them in only one memory block, the deallocation must also be unique.

    
07.02.2014 / 20:06