code bewerten



  • Das die MyListElement pointer private sind, war auch vorgesehn.
    ich hab das wohl auch beim debugen vergessen..

    wann ich this pointer verwenden muss, weiß ich selber. unser java lehrer hat gesagt, dass er this pointer immer verwendet
    (wegen besserer uebersichtlichkeit -> bei this weiß er immer, dass sie vom obj. sind). ich hab das aber nicht konsequent durchgesetzt..
    ist glaub ich auch das gleiche wie bei _vari oder m_vari..
    this-> hat den vorteil, dass dann automatisch eine dropdownliste mit erreichbaren elementen kommt (im vc von micisoft kommt sie glaub ich immer -> find ich besser)
    oder kann man das auch im kdev einrichten (und ich weiß nicht wo) ?

    da zeigt sich wieder, dass ich das ganze noch nicht im blut hab..

    danke..morgen kommt die ueberarbeitete vers.

    @prokaion
    ich hab es anfangs teilweise hier abgeschaut (aber selber ausprogrammiert und eigentlich ist nicht mehr viel vom uhrspruenglichen uebrig):
    http://www.mathematik.uni-marburg.de/~cpp/templates/index.html
    [auf klassentemplates und dann paar mal weiter klicken]



  • .filmor schrieb:

    NULL ist C, in C++ _sollte_ man 0 nehmen.

    Das ist ja wohl geschmackssache. selbst wenn NULL als 0 definiert ist, kann man somit kennzeichnen, dass der zeiger ein nullzeiger ist. Natürlich ist das bei einer einfachen zuweisung nicht ausschalggebend, da versteht man beides, aber bei einer funktion setBuffer(NULL,0) weis man viel eher, was sache ist. Aber da bewegt man sich sehr im Bereich der persönlichen Code conventionen, und da macht eh jeder das, was er als das beste erachtet. 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.



  • - augenkrebs vermeiden (kommentare und das da => // #######################....)
    - initialisierungsliste nutzen
    - zeiger müssen im destruktor nicht auf 0 gesetzt werden, weil es sie dann sowieso nicht mehr gibt
    - präfix-operator nehmen
    - anstatt die kommentare in die funktion zu schreiben, lieber oben drüber, so wie bei doxygen. das ist ordentlicher und man kann doxygen verwenden 😉

    für NULL vs "0" => FAQ

    setBuffer(NULL,0)
    

    sieht man sowieso nur bei c-wrappern, weshalb das meiner meinung nach kein argument ist.



  • terraner schrieb:

    für NULL vs "0" => FAQ

    setBuffer(NULL,0)
    

    sieht man sowieso nur bei c-wrappern, weshalb das meiner meinung nach kein argument ist.

    std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.



  • 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.



  • otze schrieb:

    std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.

    na da sind ja ganze ~6 methoden in der iostream-lib, die zeiger übernehmen. ein bisschen wenig im vergleich zum rest der stl. aber wenn du mir vielleicht noch die name einiger anderer libs nennen könntest, die null-pointer akzeptieren, überdenke ich nochmal meine meinung. ausgenommen sind natürlich funkionen wie z.b. std::time, da die ursprünglich aus c sind und man in c das mit überladung und standard-argumenten arbeiten könnte.



  • terraner schrieb:

    otze schrieb:

    std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.

    na da sind ja ganze ~6 methoden in der iostream-lib, die zeiger übernehmen. ein bisschen wenig im vergleich zum rest der stl. aber wenn du mir vielleicht noch die name einiger anderer libs nennen könntest, die null-pointer akzeptieren, überdenke ich nochmal meine meinung. ausgenommen sind natürlich funkionen wie z.b. std::time, da die ursprünglich aus c sind und man in c das mit überladung und standard-argumenten arbeiten könnte.

    Irrlicht

    (z.b.: irr::createDevice(...,NULL); //NULL bezieht sich hier auf den EventReceiver)



  • terraner schrieb:

    - augenkrebs vermeiden (kommentare und das da => // #######################....)
    - initialisierungsliste nutzen
    - zeiger müssen im destruktor nicht auf 0 gesetzt werden, weil es sie dann sowieso nicht mehr gibt
    - präfix-operator nehmen
    - anstatt die kommentare in die funktion zu schreiben, lieber oben drüber, so wie bei doxygen. das ist ordentlicher und man kann doxygen verwenden 😉

    @augenkrebs
    ok, werd die kommentare ein bisschen umstellen..
    @init. liste / zeiger im destruktor
    hab ich geaendert
    @praefix operator
    was meinst du da genau?
    @komentare wie bei doxygen
    hm, meiner meinung sollten die komentare die funktionsweise erklaeren..
    deshalb hab ich sie auch in die funktionen geschrieben.
    werd sie aber noch ueberarbeiten..
    @NULL vs 0
    mir gefaellt eigentlich NULL besser. hat NULL geschwindigkeitsnachteile etc?
    wird es wirklich so verachtet? (es ist ja kein prob alles auf 0 umzustellen..)

    mfg aMan

    die neue vers. kommt auch gleich..



  • 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;
    }
    
    #endif
    

    mylist.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'; // postfix
    

    noch ein thread dazu

    hat 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...


Anmelden zum Antworten