Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Questions about custom allocator

10 views
Skip to first unread message

Christopher J. Pisz

unread,
Nov 24, 2016, 7:09:59 AM11/24/16
to
I found this article:
http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759

Although it predates C++11, I can't find anything more recent, so here I
am playing with the code and trying to understand it.

I get the following output from my code (listed below):

Allocated 16 bytes for a struct std::_Container_proxy
Complex Number constructed
Allocated 24 bytes for a class ComplexNumber
Complex Number copy constructed
Complex Number deconstructed
Complex Number deconstructed
Deallocated 24 bytes for a class ComplexNumber
Deallocated 16 bytes for a struct std::_Container_proxy

Why are 16 bytes allocated before space for the actual data I am putting
into the std::vector and what is a container_proxy?

When 'placement new' is called, is that when the object is being copy
constructed? and if I understand right, copy constructed into the memory
I allocated?

What is the second argument in pointer allocate(size_type n,
const_pointer = 0) ?

What is the second argument in void deallocate(pointer p, size_type) ?

This makes no sense to me. What is the max size supposed to be and why
is it a negative number? Or is this some unsigned/signed trickery?

size_type max_size() const
{
return static_cast<size_type>(-1) / sizeof(value_type);
}


Here is my listing:

// Standard Includes
#include <iostream>

//------------------------------------------------------------------------------
/// <summary>
/// A STL compliant custom allocator
/// After C++11 this changes a bit by dropping much boiler plate code
///
/// Based on Dr Dobbs article
///
http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759
/// </summary>
template <class T>
class malloc_allocator
{
public:
typedef T value_type;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef std::size_t size_type;
// typedef std::ptrdiff_t difference_type; // Gives compile error

malloc_allocator()
{
// Allocators before C++11 are expected to be stateless
}

malloc_allocator(const malloc_allocator & rhs)
{
}

~malloc_allocator()
{
}

void operator =(const malloc_allocator & rhs) = delete;

bool operator == (const malloc_allocator<T> & rhs)
{
return true;
}

bool operator != (const malloc_allocator<T> & rhs)
{
return false;
}

template <class U>
malloc_allocator(const malloc_allocator<U> &)
{
}

template <class U>
struct rebind
{
typedef malloc_allocator<U> other;
};

pointer address(reference x) const
{
return &x;
}

const_pointer address(const_reference x) const
{
return &x;
}

pointer allocate(size_type n, const_pointer = 0)
{
const size_type numBytes = n * sizeof(T);
void * p = std::malloc(numBytes);

if (!p)
{
throw std::bad_alloc();
}

std::cout << "Allocated " << numBytes << " bytes for a " <<
typeid(T).name() << std::endl;
return static_cast<pointer>(p);
}

void deallocate(pointer p, size_type)
{
const size_type numBytes = sizeof(*p);

std::free(p);
std::cout << "Deallocated " << numBytes << " bytes for a " <<
typeid(T).name() << std::endl;
}

size_type max_size() const
{
return static_cast<size_type>(-1) / sizeof(value_type);
}

void construct(pointer p, const value_type & x)
{
// 'Placement new' constructs an object at a specified location
// The custom allocator seperates allocation from construction
new(p) value_type(x);
}

void destroy(pointer p)
{
p->~value_type();
}
};

// Template specialization for void type
// Our custom allocator does not work when a container refers to void
pointers.
// We refer to sizeof(T) and T& which is not legal when T is void.
// Therefore we must specialize.
// Leaves out everything except what is needed for referring to void
pointers
template<> class malloc_allocator<void>
{
typedef void value_type;
typedef void * pointer;
typedef const void * const_pointer;

template <class U>
struct rebind
{
typedef malloc_allocator<U> other;
};
};

//------------------------------------------------------------------------------
class ComplexNumber
{
public:

ComplexNumber(double realPart, double complexPart);
ComplexNumber(const ComplexNumber & rhs);
virtual ~ComplexNumber();

protected:

double m_realPart;
double m_complexPart;
};

//------------------------------------------------------------------------------
ComplexNumber::ComplexNumber(double realPart, double complexPart)
:
m_realPart(realPart)
, m_complexPart(complexPart)
{
std::cout << "Complex Number constructed" << std::endl;
}

//------------------------------------------------------------------------------
ComplexNumber::ComplexNumber(const ComplexNumber & rhs)
:
m_realPart(rhs.m_realPart)
, m_complexPart(rhs.m_complexPart)
{
std::cout << "Complex Number copy constructed" << std::endl;
}

//------------------------------------------------------------------------------
ComplexNumber::~ComplexNumber()
{
std::cout << "Complex Number deconstructed" << std::endl;
}

//------------------------------------------------------------------------------
void RunCustomAllocator()
{
std::vector<ComplexNumber, malloc_allocator<ComplexNumber> > myVector;
ComplexNumber number(1, 1);
myVector.push_back(number);
}

//------------------------------------------------------------------------------
int main(int argc, char * argv[])
{
// RunNoMemoryManagement();
// RunSimpleMemoryManagement();

RunCustomAllocator();

return 0;
}

mark

unread,
Nov 24, 2016, 7:38:46 AM11/24/16
to
On 2016-11-24 13:09, Christopher J. Pisz wrote:
> I found this article:
> http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759
>
> Although it predates C++11, I can't find anything more recent, so here I
> am playing with the code and trying to understand it.
>
> I get the following output from my code (listed below):
>
> Allocated 16 bytes for a struct std::_Container_proxy
> Complex Number constructed
> Allocated 24 bytes for a class ComplexNumber
> Complex Number copy constructed
> Complex Number deconstructed
> Complex Number deconstructed
> Deallocated 24 bytes for a class ComplexNumber
> Deallocated 16 bytes for a struct std::_Container_proxy
>
> Why are 16 bytes allocated before space for the actual data I am putting
> into the std::vector and what is a container_proxy?

Probably iterator tracking / debugging:
<https://hadibrais.wordpress.com/2013/11/13/dissecting-the-c-stl-vector-part-2-constructors/>

> What is the second argument in pointer allocate(size_type n,
> const_pointer = 0) ?
>
> What is the second argument in void deallocate(pointer p, size_type) ?

http://en.cppreference.com/w/cpp/memory/allocator

> This makes no sense to me. What is the max size supposed to be and why
> is it a negative number? Or is this some unsigned/signed trickery?
>
> size_type max_size() const
> {
> return static_cast<size_type>(-1) / sizeof(value_type);
> }

For unsigned types, -1 is equivalent to numeric_limits<size_type>::max().

0 new messages