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

Questions about custom allocator

9 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