I have two templates for creating custom dispensers; the first works automatically if it is used in a custom type:
template<> class std::allocator<MY_TYPE> { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef MY_TYPE* pointer; typedef const MY_TYPE* const_pointer; typedef MY_TYPE& reference; typedef const MY_TYPE& const_reference; typedef MY_TYPE value_type; template <class U> struct rebind { typedef std::allocator<U> other; }; pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) { return reinterpret_cast<pointer>(ALLOC_FUNC(n * sizeof(T))); } void construct(pointer p, const_reference val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } void deallocate(pointer p, size_type n) { FREE_FUNC(p); } size_type max_size() const throw() {
The second is used when we want to have our own dispenser for a predefined type with a standard dispenser, for example char, wchar_t, std :: string, etc.:
namespace MY_NAMESPACE { template <class T> class allocator; // specialize for void: template <> class allocator<void> { public: typedef void* pointer; typedef const void* const_pointer; // reference to void members are impossible. typedef void value_type; template <class U> struct rebind { typedef allocator<U> other; }; }; template <class T> class allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template <class U> struct rebind { typedef allocator<U> other; }; allocator() throw() { } template <class U> allocator(const allocator<U>& u) throw() { } ~allocator() throw() { } pointer address(reference r) const { return &r; } const_pointer address(const_reference r) const { return &r; } size_type max_size() const throw() { // return ~size_type(0); -- Error, fixed according to Constantin comment return std::numeric_limits<size_t>::max()/sizeof(T); } pointer allocate(size_type n, allocator<void>::const_pointer hint = 0) { return reinterpret_cast<pointer>(ALLOC_FUNC(n * sizeof(T))); } void deallocate(pointer p, size_type n) { FREE_FUNC(p); } void construct(pointer p, const_reference val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } }; template <class T1, class T2> inline bool operator==(const allocator<T1>& a1, const allocator<T2>& a2) throw() { return true; } template <class T1, class T2> inline bool operator!=(const allocator<T1>& a1, const allocator<T2>& a2) throw() { return false; } }
The first template above for your own specific type does not require additional processing, but is automatically used by standard container classes. The second template requires further work when using the standard type. For example, for std :: string, you need to use the following construct when declaring variables of this type (this is easiest with typedef):
std::basic_string<char>, std::char_traits<char>, MY_NAMESPACE::allocator<char> >
Stefan Rådström Feb 12 '09 at 17:07 2009-02-12 17:07
source share