Why is this S ++ STL allocator not highlighted?

I am trying to write a specialized STL std::allocator that is derived from std::allocator , but somehow all the allocate() calls go to the base class. I narrowed it down to this code:

 template <typename T> class a : public std::allocator<T> { public: T* allocate(size_t n, const void* hint = 0) const { cout << "yo!"; return 0; } }; int main() { vector<int, a<int>> v(1000, 42); return 0; } 

I expect "Yo!" to print, and then some terrible mistake, because I actually don't highlight anything. Instead, the program runs fine and does not print anything. What am I doing wrong?

I get the same results in gcc and VS2008.

+12
c ++ stl allocation
Feb 12 '09 at 1:25
source share
4 answers

You will need to provide a feedback member template and other elements listed in the distributor requirements in the C ++ standard. For example, you need a template copy constructor that accepts not only allocator<T> , but also allocator<U> . For example, one code may be executed, which will probably look like std :: list,

 template<typename Allocator> void alloc1chunk(Allocator const& alloc) { typename Allocator::template rebind< wrapper<typename Allocator::value_type> >::other ot(alloc); // ... } 

The code will not work if the correct rewrite pattern does not exist or if there is no corresponding copy constructor. Nothing will come in handy if you guess what the requirements are. Sooner or later you will have to make code that relies on one part of these dispenser requirements, and the code will not work because your dispenser violates them. I recommend that you look at them in some working draft of your copy of the Standard in 20.1.5 .

+6
Feb 12 '09 at 3:01
source share

In this case, the problem is that I did not override the allocator re-binding element. This version works (in VS2008):

 template <typename T> class a : public std::allocator<T> { public: T* allocate(size_t n, const void* hint = 0) const { cout << "yo!"; return 0; } template <typename U> struct rebind { typedef a<U> other; }; }; int main() { vector<int, a<int>> v(1000, 42); return 0; } 

I found this by debugging STL headers.

Whether this will work or not will depend entirely on the implementation of STL, although, I think, in the end, Klaim is right that it should not be done that way.

+4
Feb 12 '09 at 2:12
source share

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() { // return ~size_type(0); -- Error, fixed according to Constantin comment return std::numeric_limits<size_t>::max()/sizeof(MY_TYPE); } }; 

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> > 
+2
Feb 12 '09 at 17:07
source share

The following code prints "yo" as expected - what you saw was our old friend "undefined behavior".

 #include <iostream> #include <vector> using namespace std; template <typename T> class a : public std::allocator<T> { public: T* allocate(size_t n, const void* hint = 0) const { cout << "yo!"; return new T[10000]; } }; int main() { vector<int, a<int> > v(1000, 42); return 0; } 

Edit: I just checked the C ++ standard regarding the default allocator. There is no prohibition of inheritance from him. In fact, as far as I know, there is no such prohibition in any part of the Standard.

+1
Feb 12 '09 at 1:35
source share



All Articles