Template-template problem -> "teufelskreis"
-
ich habe eine klasse die folgendermaßen aussieht:
template<class TId/*identifier*/, class TData/*datatype*/, class TPCreation> class MyClass{ /*code*/ };jetzt will ich einen solchen datentyp erstellen:
typedef MyClass<int, float,PCreateUsingNew<MyClass<int, float, ...> > my_type;und da ist auch schon das problem, 'PCreateUsingNew<class T>' benötigt den zu erstellenden typ für den allocater, da dieser typ aber wiederum CCreateUsingNew enthällt, entsteht eine art teufelskreis und ich habe keine möglichkeit die klasse zu erstellen.

-
Falls das ein normaler Allokator sein soll, wie ihn die Standardbibliothek kennt, ist es nicht zwingend erforderlich, den Typ gleich korrekt anzugeben.
template<class T, class Alloc> class Foo { typedef typename Alloc::template rebind<Foo>::other real_alloc; // C++03 using real_alloc = typename std::allocator_traits<Alloc>::template rebind_alloc<Foo>; // C++11 }; typedef Foo<int, std::allocator<void> > my_foo;Alternativ könnte man auch einen Templatetemplateparamter verwenden.
-
also, hier mal der code zweier meiner allocatoren:
// implementation of the CreationPolicy // -> creates objects using a straight call to the new operator template <class T> class PCreateUsingNew{ public: static T* create(){ return new T; } static void destroy(T* p){ delete p; } };// c: PCreateUsingNew // implementation of the CreationPolicy // -> creates objects using a call to std::malloc, // followed by call to the placement new operator template <class T> class PCreateUsingMalloc{ public: static T* create(){ void* p = std::malloc(sizeof(T)); if (!p) return 0; return new(p) T; } static void destroy(T* p){ p->~T(); std::free(p); } };// c: PCreateUsingMalloc
-
Das hier:
static T* create(){ void* p = std::malloc(sizeof(T)); if (!p) return 0; return new(p) T; }Ist doch nicht sicher, oder?
Sollte es nichtstatic T* create() { void* p = std::malloc(sizeof(T)); if (!p) return 0; try { return new(p) T; } catch( ... ) { std::free( p ); throw; } }sein?
-
Jede beliebige Form von Indirektion hilft. Ein zusätzliches typedef-/alias-template wie die Standardallokatoren. Oder aber, falls die Allokatoren immer zustandslos sind, den Typparemeter aus der Klasse entfernen und statt dessen Templatefunktionen verwenden.
Oder eben, wie schon angesprochen, die Allokationspolicy durch enen Templatetemplateparameter spezifizieren (im Stile von Alexandrescus PB-Designs).
-
Ist doch nicht sicher, oder?
Sollte es nichtsicher ist immer relativ, deins ist auf jeden fall sicherer, aber in den meisten fällen reicht meine variante vollkommen (zumindest bis jetzt
)Ist doch nicht sicher, oder?
Sollte es nichtich hab 'modern c++ design by andrei alexandrescu' hier liegen, weiß einer die seitenzahl?

-
gamer8o4 schrieb:
sicher ist immer relativ
Nein.
-
gamer8o4 schrieb:
sicher ist immer relativ, deins ist auf jeden fall sicherer, aber in den meisten fällen reicht meine variante vollkommen (zumindest bis jetzt
)Du meinst, du hast noch nie einen Konstruktor gesehen, der eine Exception wirft? Auch wenns ein Default-Konstruktor ist, sowas sollte man nicht im Vornherein ausschliessen.
<:xmas2:>
-
habs
andrei alexandrescu hat mich (mal wieder) gerettet!
danke für den tipp und ich habe meine allocatoren übrigens überarbeitet wie ihr das vorgeschlagen habt (try-catch blöcke)
-
Sone schrieb:
static T* create() { void* p = std::malloc(sizeof(T)); if (!p) return 0; try { return new(p) T; } catch( ... ) { std::free( p ); throw; } }
Das ist korrekt. Ausserdem absolut super, dass du gelernt hast, dass das bei destroy nicht nötig ist, weil Destruktoren eh nie werfen dürfen.Es ist immer eine nette Übung, Code mit try/catch umzuschreiben, dass kein try/catch nötig ist. Führt oft zu lesbarem Code.
template <typename T> class malloc_guard { T *p; public: malloc_guard() { p = std::malloc(sizeof(T)); } ~malloc_guard() { if (p) std::free(p); } // if (p) fürs Herausoptimieren T* get() { return p; } T* release() { T *ptr=p; p=0; return ptr; } }; static T* create() { malloc_guard<T> memory; if (memory.get()) new (memory.get()) T; return memory.release(); }