Allocator für STL-Container: ein paar Fragen
-
der Anfangs mit einer unveränderlichen Kapazität initialisiert wird.
das ist kein problem...
so was hab ich so gar vor einiger zeit mal geschrieben gehabt:#ifndef H_MY_ALLOCATOR_ALLOCATE_AT_STACK_INCLUDED_20091202221055 #define H_MY_ALLOCATOR_ALLOCATE_AT_STACK_INCLUDED_20091202221055 #include <cassert> #include <cstddef> #include <new> #include <stdexcept> #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4510) //default constructor could not be generated # pragma warning(disable: 4610) //can never be instantiated - user defined constructor required #endif #include <type_traits> #ifdef _MSC_VER # pragma warning(pop) #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4100) //http://msdn.microsoft.com/en-us/library/26kb9fy0.aspx "C4100 can also be issued when code calls a destructor on a otherwise unreferenced parameter of primitive type. This is a limitation of the Visual C++ compiler." #endif namespace MY_NAMESPACE_NAME { template <typename T, std::size_t count> struct stack_allocator; template <std::size_t count> struct stack_allocator <void, count> { public: typedef void* pointer; typedef const void* const_pointer; typedef void value_type; template <typename U> struct rebind { typedef stack_allocator<U, count> other; }; }; template <typename T, std::size_t count> struct stack_allocator { public: enum { allocating_size = count, allocating_byte = allocating_size*sizeof(T) }; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; template <typename U> struct rebind { typedef stack_allocator<U, count> other; }; stack_allocator() throw() : empty(true) {} stack_allocator(const stack_allocator&) throw() : empty(true) {} template <typename U, std::size_t Ucount> stack_allocator(const stack_allocator<U, Ucount>&) throw() : empty(true) {} ~stack_allocator() throw() { assert(empty); empty; //we dont want a warning at release-mode } pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, stack_allocator<void, 0>::const_pointer /*hint*/ = 0) { if(n > allocating_size) throw std::bad_alloc(); if(!empty) throw std::bad_alloc(); empty = false; return reinterpret_cast<pointer>( data.data ); } void deallocate(pointer p, size_type /*n*/) { assert( p == reinterpret_cast<pointer>(data.data) ); p; //we dont want a warning at release-mode empty = true; } size_type max_size() const throw() { return allocating_size; } void construct(pointer p, const_reference val) { new ( static_cast<void*>(p) ) T(val); } void destroy(pointer p) { p->~T(); } private: bool empty; union { typename std::tr1::aligned_storage<sizeof(T), std::tr1::alignment_of<T>::value>::type alignment; char data[allocating_byte]; } data; }; template <typename T, std::size_t Tc, typename U, std::size_t Uc> bool operator== (const stack_allocator<T, Tc>& /*lhs*/, const stack_allocator<U, Uc>& /*rhs*/) throw() { return true; } template <typename T, std::size_t Tc, typename U, std::size_t Uc> bool operator!= (const stack_allocator<T, Tc>& /*lhs*/, const stack_allocator<U, Uc>& /*rhs*/) throw() { return false; } }//namespace MY_NAMESPACE_NAME #ifdef _MSC_VER # pragma warning(pop) #endif #endif //#ifndef H_MY_ALLOCATOR_ALLOCATE_AT_STACK_INCLUDED_20091202221055
der allokator wird nur nie mit einer liste funktionieren, sondern lediglich mit nem vektor... außerdem muss man dann manuell ein reserve am anfang machen, was ein wenig nervig ist - aber mir hat es damals so gereicht^^
das problem bei einem allokator, der auch mit listen etc geht, ist halt, dass man dort lookups (nach freiem speicher) braucht - und somit wird man auch wieder langsamer... listen reservieren ja speicher nur immer für einen knoten auf einmal - obwohl man erst mal versuchen könnte, mehrere knoten auf einmal zu allokieren und nur wenn das schief geht, einzeln allokieren könnte - aber naja, man kann ja nicht alles haben
was ich mir bei der zeile im dtor gedacht hatte (empty; //we dont want a warning at release-mode
), kann ich dir nicht mehr sagen xD
das #ifdef-zeugs um#include <type_traits>
ist leider notwendig, weil sonst nen haufen warnings kommen - zumindest beim MSVC9
ist ein wenig fail, aber kann man halt nix machenwas genau kann man dann mit dem Allokator-Parameter bei den Container-CTors erreichen
man kann erreichen, dass der copy-ctor aufgerufen wird... und man muss das template-argument nicht mitschreiben...
bb