code bewerten
-
verbesserte version:
ich hab auch die deleteCurrentElement() methode umgebaut.
welche ist den beser (alte/neue)?@die ///####/// komentare
die trennen den haeder von der implementierung. ich habe jetzt nur noch eine zeile.
warum kann man eigentlich bei templates den code nicht von der implementierung trennen?mylistelement.h
#ifndef MYLISTELEMENT_H #define MYLISTELEMENT_H // #include "mylist.h" template <class T> class MyList; /** @author Adam Celarek */ template <class T> class MyListElement { private: MyListElement(T* element); ~MyListElement(); MyListElement* m_next; MyListElement* m_prev; T* m_element; friend class MyList<T>; }; ///########################################################################################/// ///#### con- / destructor template <class T> MyListElement<T>::MyListElement(T* element) : m_element(element) { m_next = NULL; m_prev = NULL; } template <class T> MyListElement<T>::~MyListElement() { delete m_element; } #endifmylist.h
#ifndef MYLIST_H #define MYLIST_H #include "mylistelement.h" /** @author Adam Celarek */ template <class T> class MyList { public: MyList(); ~MyList(); void append(T* element); // appends T* element and resets the next() function bool deleteCurrentElement(); // delete previously returned_element. so a current() after a // deleteCurrentElement() will always give a NULL // returns false if returned_element is NULL or if list_size is 0 unsigned int size() const; T* next(); // returns next_element; if the last element of the list // have been already returned, the function returns NULL T* current() const; T* first(); // returns first elem, and resets the next() function private: MyListElement<T>* m_first_element; MyListElement<T>* m_returned_element; // this element may be deleted / was returned by next (if not, then it's NULL) MyListElement<T>* m_next_element; // next element, that will be returned MyListElement<T>* m_last_element; unsigned int m_list_size; }; ///########################################################################################/// ///#### con/de-tructors #### template <class T> MyList<T>::MyList() { m_first_element=NULL; m_returned_element=NULL; m_next_element=m_first_element; m_list_size=0; } template <class T> MyList<T>::~MyList() { MyListElement<T>* current_element; current_element = m_first_element; while (current_element) // deletes the whole list; beginning at the first element { m_first_element = current_element->m_next; delete current_element; current_element=m_first_element; } } ///#### acces #### /*! \fn MyList::append() */ template <class T> void MyList<T>::append(T* element) { // 2 cases: // 1. there are no elements in the list // 2. there are elements in the list MyListElement<T>* new_element = new MyListElement<T>(element); if (m_list_size == 0) // case 1: no elements in the list { m_first_element=new_element; m_last_element=new_element; } else // case 2: the new element will be appended to the end of the list { m_last_element->m_next = new_element; new_element->m_prev = m_last_element; m_last_element = new_element; } first(); // resets the next() function m_list_size++; } /*! \fn MyList::deleteCurrentElement() */ template <class T> bool MyList<T>::deleteCurrentElement() { // no elements if (m_returned_element==NULL || m_list_size==0) { return false; } // changing pointers if (m_returned_element->m_next != NULL) m_returned_element->m_next->m_prev = m_returned_element->m_prev; if (m_returned_element->m_prev != NULL) m_returned_element->m_prev->m_next = m_returned_element->m_next; // if deleteting the first element if (m_returned_element == m_first_element) { m_first_element = m_next_element; } // if deleteting the last element if (m_returned_element == m_last_element) { m_last_element = m_returned_element->m_prev; } delete m_returned_element; m_list_size--; return true; } /*! \fn MyList::first() */ template <class T> T* MyList<T>::first() { m_returned_element = m_first_element; m_next_element = m_first_element->m_next; if (m_returned_element != NULL) return m_returned_element->m_element; else return NULL; } /*! \fn MyList::next() */ template <class T> T* MyList<T>::next() { if (m_next_element==NULL) { m_returned_element = NULL; // the m_next_element is only NULL, return NULL; // if the last position was already returned. } // it's even a check, so that the else clause can't make a segmentation fault else { m_returned_element = m_next_element; m_next_element = m_returned_element->m_next; return m_returned_element->m_element; } } /*! \fn MyList::current() */ template <class T> T* MyList<T>::current() const { if(m_returned_element!=NULL) return m_returned_element->m_element; else return NULL; } ///#### properties #### /*! \fn MyList::size() */ template <class T> unsigned int MyList<T>::size() const { return m_list_size; } #endif
-
aMan schrieb:
@praefix operator
was meinst du da genau?int i = 0; cout << "1: " << i << '\n'; cout << "2: " << ++i << ", " << i << '\n'; // präfix cout << "3: " << i++ << ", " << i << '\n'; // postfixhat NULL geschwindigkeitsnachteile etc?
wird es wirklich so verachtet? (es ist ja kein prob alles auf 0 umzustellen..)@topic speed: nein, weil es ein macro ist.
nein, imo ist es zum großen teil geschmackssache, ob man es einsetzt.
-
ok, danke..
@praefix operator
was das ist weiß ich schon, ich weiß nur nicht, wo ich ihn verwenden sollte..mfg aman..
-
aMan schrieb:
was das ist weiß ich schon, ich weiß nur nicht, wo ich ihn verwenden sollte..
Da, wo du m_list_size rauf- und runterzählst.
-
hmm..
warum ist da ein praefix oper. besser als ein post oper.?
-
aMan schrieb:
warum ist da ein praefix oper. besser als ein post oper.?
In dem Fall ist es egal, weil du den Rückgabewert nicht auswertest und es sich um einen eingebauten Datentyp handelt.
Aber es kann nicht schaden, wenn du dir angewöhnst, die Präfixversion zu benutzen, wenn es egal ist, damit du es automatisch richtig machst, wenn es nicht egal ist. Sieh einfach die Präfixversion als den Normalfall an und benutz die Postfixversion nur dort, wo du wirklich den "alten" Wert als Rückgabewert brauchst.
-
MFK schrieb:
otze schrieb:
Ich bin zumindest sehr gut damit gefahren, nullzeiger mit NULL zu bezeichnen, damit ich einen zeiger sehr schnell von anderen parametern(die zufälligerweise auch 0 sind) unterscheiden kann, wenn ich den Code überfliege.
Man darf sich dann nur nicht wundern, wenn bei einem NULL-Parameter die Überladung für int aufgerufen wird.
sicher. nur gut, dass es keinen sinnvollen Fall gibt, bei dem man als argument entweder einen int oder einen null-zeiger erwarten kann

-
otze schrieb:
nur gut, dass es keinen sinnvollen Fall gibt, bei dem man als argument entweder einen int oder einen null-zeiger erwarten kann

Nur gut, dass jeder Programmierer auf der Welt nur sinnvolle Überladungen erstellt

-
aMan schrieb:
warum kann man eigentlich bei templates den code nicht von der implementierung trennen?
Weil der Compiler bei der Verarbeitung des Templates wissen muß, (a) wie das Template aufgebaut ist (Quelltext) und (b) mit welchen Typen es verwendet wird (instantiierung). Die Informationen hat er nur zusammen, wenn du den Code direkt in dein Programm inkludierst.
-
CStoll schrieb:
aMan schrieb:
warum kann man eigentlich bei templates den code nicht von der implementierung trennen?
Weil der Compiler bei der Verarbeitung des Templates wissen muß, (a) wie das Template aufgebaut ist (Quelltext) und (b) mit welchen Typen es verwendet wird (instantiierung). Die Informationen hat er nur zusammen, wenn du den Code direkt in dein Programm inkludierst.
Könnte man sich die Codeguards ansonsten nicht auch sparen?
Oder gibt es noch andere solche fälle, wo Definitionen im Header stehen?
-
roan312 schrieb:
Könnte man sich die Codeguards ansonsten nicht auch sparen?
Oder gibt es noch andere solche fälle, wo Definitionen im Header stehen?Includeguards (ich nehme an, dass du die meinst) haben mit Definitionen in Headerdateien nichts zu tun. Include-Guards verhindern das mehrfache Einbinden einer Headerdatei in einer Übersetzungseinheit. Damit lassen sich z.B. unendliche Includerekursionen verhindern. Definitionen in Headerdateien können nur zwischen mehreren Übersetzungseinheiten Probleme machen.
-
MFK schrieb:
roan312 schrieb:
Könnte man sich die Codeguards ansonsten nicht auch sparen?
Oder gibt es noch andere solche fälle, wo Definitionen im Header stehen?Includeguards (ich nehme an, dass du die meinst) haben mit Definitionen in Headerdateien nichts zu tun. Include-Guards verhindern das mehrfache Einbinden einer Headerdatei in einer Übersetzungseinheit. Damit lassen sich z.B. unendliche Includerekursionen verhindern. Definitionen in Headerdateien können nur zwischen mehreren Übersetzungseinheiten Probleme machen.
Das mit den Includerekursionen stimmt, daran hab ich nicht gedacht,
aber mehrfach Definitionen innerhalb einer Übersetzungseinheit machen auch schwierigkeiten.EDIT:
class foo {}; class foo {};Redifinition if class foo...
-
ok, danke leuds..
koennt ihr mir noch sagen, welche der beiden (alt und neu) deleteCurrentElement() methoden besser ist?
-
otze schrieb:
std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.
man könnte sich das auch sparen indem man sowas schreibt:
void pubsetbuf(size_t length, char* pointer = 0);somit wäre es dem autor der funktion überlassen, ob er 0 oder NULL verwendet, da er in jedem falle sofort sieht, dass hier ein zeiger genullt wird.
imo ist diese lösung sogar zu bevorzugen, weil hier ein sprachmittel von c++ genutzt wird, dass funktionsaufrufe erleichtern soll.