U
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