I wrote a custom allocator. However, the Clang/LLVM compiler started complaining about mismatching a constructor for initialization of my allocator when I added list.sort()
into main()
.
Though the code is a bit long, this is the minimum workable snippet:
#include <iostream>
#include <ctime>
#include <list>
#include <limits>
template<typename T, int start = 16, int ratio = 2, int thrsh = 65536>
class Allocator
{
private:
T *avsp;
int used, vcnt;
struct _block
{ struct _block *next;
T nodes[1];
} *pool, *pblock;
public :
// typedefs
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;
public :
// convert an allocator<T> to allocator<U>
template<typename U>
struct rebind
{
typedef Allocator<U, start, ratio, thrsh> other;
};
public :
explicit Allocator()
{
avsp = NULL;
used = 0;
vcnt = 0;
pool = NULL;
pblock = NULL;
}
~Allocator() {}
explicit Allocator(Allocator const&) {}
template<typename U>
explicit Allocator(Allocator<U, start, ratio, thrsh> const&) {}
// address
pointer address(reference r)
{
return &r;
}
const_pointer address(const_reference r)
{
return &r;
}
// memory allocation
pointer allocate(size_type cnt = 1, // SHOULD ALWAYS BE ONE
typename std::allocator<void>::const_pointer = 0)
{
(void)cnt;
if (avsp == NULL)
{
if (vcnt == 0)
{
pblock = pool;
pool = NULL;
if (used == 0)
vcnt = (used = start);
else
vcnt = (used < thrsh) ? (used *= ratio) : (used = thrsh);
if (pool != NULL)
std::cerr << "Potential Memory Leak." << std::endl; // Compatibility Purpose Only
pool = static_cast<struct _block*>(malloc((sizeof(*pblock)) +
(sizeof(pblock->nodes)) * (size_t)(used - 1)));
if (pool == NULL)
std::cerr << "Memory Allocation Failure." << std::endl; // Compatibility Purpose Only
pool->next = pblock;
}
return &(pool->nodes[--vcnt]);
}
else
{
// NOT IMPL: AVSP
exit(EXIT_FAILURE);
}
// NEVER REACH !!
exit(EXIT_FAILURE);
}
void deallocate(pointer p, size_type)
{
// NOT IMPL: AVSP
(void)p;
}
// size
size_type max_size() const
{
return std::numeric_limits<size_type>::max() / sizeof(T);
}
// construction/destruction
void construct(pointer p, const T& t)
{
new(p) T(t);
}
void destroy(pointer p)
{
p->~T();
}
template<typename U>
bool operator==(const Allocator<U, start, ratio, thrsh>&) const
{
return true;
}
template<typename U>
bool operator!=(const Allocator<U, start, ratio, thrsh>&) const
{
return false;
}
};
int main (void)
{
std::list<uint32_t, Allocator<uint32_t>> list;
for (int cnt = 0; cnt < 1 << 27; cnt++)
list.push_back(rand());
list.sort(); // <-- Problems Here
return 0;
}
This is the error message:
/usr/include/c++/4.6/bits/move.h:127
error: no matching constructor for initialization of 'Allocator<std::_List_node<unsigned int>, 16, 2, 65536>'
/usr/include/c++/4.6/bits/allocator.h:163:4:
in instantiation of function template specialization 'std::swap<Allocator<std::_List_node<unsigned int>, 16, 2, 65536> >' requested here
/usr/include/c++/4.6/bits/stl_list.h:1185:4:
in instantiation of member function 'std::__alloc_swap<Allocator<std::_List_node<unsigned int>, 16, 2, 65536>, false>::_S_do_it' requested here
/usr/include/c++/4.6/bits/list.tcc:375:11:
in instantiation of member function 'std::list<unsigned int, Allocator<unsigned int, 16, 2, 65536> >::swap' requested here
<this-file>.cpp:??:10:
in instantiation of member function 'std::list<unsigned int, Allocator<unsigned int, 16, 2, 65536> >::sort' requested here
Types with explicit
copy constructors do not meet the CopyConstructible
requirements, and allocators must be CopyConstructible. This was clarified by https://wg21.link/lwg2081
So you need to remove the explicit
from your copy constructor. To be safe (and ensure portability to all standard library implementations) you should probably also remove explicit
from the converting constructor template.