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 machen 😞

    was 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


Anmelden zum Antworten