Was tun, falls NULL Zeiger uebergeben werden?
-
In letzter Zeit habe ich bemerkt, mir immer wieder die Finger mit ein und dem gleichen Code wund zu schreiben, für ein und die gleiche Aufgabe, an der aber immer unterschiedliche Datentypen beteiligt waren. Deshalb habe ich beschlossen, ein template zu schreiben, das mir meine wunden Finger in Zukunft ersparen soll.
Derzeit sieht es so aus:
template <typename T> class Liste{ T* data; unsigned amountOf; unsigned nextAlloc; bool seriousError; public: Liste(); ~Liste(); bool getError(); bool insert(const T& ToAdd); bool drop(const T& ToAdd); bool init(FILE* ListFile, unsigned SizeOfElem, unsigned char separator); };Speziell bei der Funktion insert(), die ein weiteres Element des Typs T hinzufügen können soll, gibt es Probleme.
Es ist nämlich speziell in jenen Fällen, in denen der Typ T ein Zeiger ist, NICHT ERWÜNSCHT, dass ein NULL-Zeiger in die Liste hineingesteckt werden kann, vielmehr soll in solchen Fällen nämlich false zurück gegeben werden.
Jetzt wäre es irgendwie toll, wenn man den Datentyp T in einer IF-Abfrage erst darauf hin überprüfen könnte, ob es ein Zeiger ist oder nicht.
Wenn es nämlich kein Zeiger ist, sondern irgend ein komplettes Objekt irgend einer Klasse, dann kritisiert der Compiler nämlich eine if-Anweisung wieif(ToAdd==NULL)weil die Datentypen nicht vergleichbar sind. Im übrigen wäre dieser Vergleich wohl auch nicht sehr sinnvoll - in den meisten Fällen. Falls aber const T& irgend ein Zeiger Typ sein sollte, dann soll natürlich auf alle vermieden werden, dass die NULL-Zeiger in der Liste landen.
Wäre schön, wenn jemandem ein Ausweg aus dem Dilemma einfällt, dass man ja nicht wissen kann, ob T ein Zeiger ist oder nicht.
Thx
-
Spezialisier doch die Methode für Zeigertypen:
template <typename T> bool Liste<T*>::insert(const T& ToAdd) { if (ToAdd == 0) return false; // ... }/EDIT: Das klappt so nicht. Man muss die ganze Klasse spezialisieren, nicht nur die Funktion.
-
Alternativ kannst du eine "check policy" verwenden, dann musst du nicht gleich die ganze Liste spezialisieren:
template <class T> class ListElementCheckPolicy; //default: template <class T> class ListElementCheckPolicy { public: static bool CheckElement(T const&) { return true; } }; //für pointer: template <class T> class ListElementCheckPolicy<T*> { public: static bool CheckElement(T* const& t) { return t != 0; } }; template <typename T, class P = ListElementCheckPolicy<T> > class List { public: // ... bool Insert(T const& t) { if (!P::CheckElement(t)) return false; // ... return true; } };
-
anstatt einer policy könnte man es aber auch so machen:
//wenn der compiler static const nicht mitmacht, nimm stattdessen ne enum template<class T> struct IsPointer{ static const bool value=false; }; template<class T> struct IsPointer<T*>{ static const bool value=true; }; template <typename T> class List { public: // ... bool Insert(T const& t) { if (IsPointer<T>::value&&t==NULL) return false; // ... return true; } };//edit bin mir grad net sicher, ob der compiler merkt, dass t==NULL nur dann aufgerufen wird, wenn IsPointer true ist. mal testen
//edit 2 natürlich net. narf. müsste man also nen "compilerruhigstellcast" machen. das nimmt meiner Lösung natürlich jeden reiz

-
@otze: wie willst du das denn casten?
-
hustbaer schrieb:
@otze: wie willst du das denn casten?
if (IsPointer<T>::value&&*(int*)&t==0)da dieser cast nur dann passiert, wenn IsPointer<T>::value==true ist, kann man das bedenkenlos machen.
klappt natürlich nicht bei methodenzeigern