Those who know what allocator::rebind does, please put your hands up.
I write my own allocator, and I override the allocator::pointer so that it points to my object instead of a normal pointer. And I use this when I construct an STL container.
I use shared memory to maintain a look-up table that can be accessed from multiple applications. Since different processes will map the shared memory to a different base address, pointer code in STL containers don't work. I wrote my own pointer class that actually stores the offset and when dereferenced will automatically apply the base address.
While, this is within the standard, this is so obscure that it only worked with MSVC7.0-7.1 and icpc7-9. g++ never supported it and even the latest version of MSVC don't support it. Most STL libraries simply need to assume that you are working with a regular pointer.
This is what a custom allocator looks like (M::ptr contains the base address):
template<class T, class M>
class var_allocator
{
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef relative_ptr<T,M> pointer;
typedef const_relative_ptr<T,M> const_pointer;
typedef T& reference;
typedef const T& const_reference;
var_allocator() {}
var_allocator(const var_allocator<T,M> &) {}
template<class U>
var_allocator(const var_allocator<U,M> &) {}
pointer address(reference ref) const { return &ref; }
const_pointer address(const_reference ref) const { return &ref; }
void* raw_allocate( size_type size , size_type n , void* )
{
return mm_malloc(M::Ptr, size * n);
}
void raw_deallocate( void* ptr )
{
mm_free(M::Ptr, ptr);
}
pointer allocate( size_type n , const void* )
{
return (pointer)raw_allocate( sizeof(T), n, NULL);
}
pointer allocate( size_type n )
{
return (pointer)raw_allocate( sizeof(T), n, NULL);
}
void* _Charalloc(size_type size)
{
return raw_allocate(size, 1, NULL);
}
void deallocate( pointer ptr, size_type )
{
raw_deallocate(ptr);
}
void deallocate( pointer ptr )
{
raw_deallocate(ptr);
}
void deallocate( void* ptr, size_type )
{
raw_deallocate(ptr);
}
void deallocate( void* ptr )
{
raw_deallocate(ptr);
}
void construct(const relative_ptr<T,M> &ptr, const T& val)
{
new ((void *)ptr) T (val);
}
template <class U> void construct(U* ptr, const U& val)
{
new (ptr) U (val);
}
template <class U> void construct(U *ptr, int)
{
new (ptr) U;
}
template <class U> void construct(relative_ptr<U,M> &ptr, const U& val)
{
new ((void *)ptr) U (val);
}
template <class U> void construct(relative_ptr<U,M> &ptr, int)
{
new ((void *)ptr) U;
}
#ifdef _WIN32
#pragma warning(disable: 4100)
#endif
template <class U> void destroy(U *ptr)
{
(*ptr).~U();
}
#ifdef _WIN32
#pragma warning(default: 4100)
#endif
template <class U> void destroy(relative_ptr<U,M> &ptr)
{
ptr->~U();
}
size_type max_size() const
{
return mm_core_size(M::Ptr) / sizeof(T);
}
template <class U>
struct rebind
{
typedef var_allocator<U,M> other;
};
};
template<class M>
class var_allocator<void,M>
{
typedef relative_ptr<void,M> pointer;
};