operator ++ - *this rückgabe



  • Also jetzt blick ich irgendwie gar nimma so durch, vorhin hat hier irgendjemand folgenden link gepostet --> http://www.c-plusplus.net/forum/viewtopic-var-t-is-39454.html
    Hab ich mir jetzt halt mal angeschaut, und dann kam der Code hier vor:

    #include <iostream>
    
    class foo
    {
    public:
        foo(int nr):m_nr(nr) {}
    
        foo & operator++ ()    // Präfix
        {
            ++m_nr;
            return *this;
        }
    
        const foo operator++ (int)  // die Postfix-Version bekommt ein int-dummy Parameter
        {                           // um sie von der Präfix-Version unterscheiden zu können
            foo tmp(*this);
            ++(*this);       // benuzt den Präfix-Operator
            return tmp;
        }
    private:
        int m_nr;
    };
    
    int main()
    {
    
        return 0;
    }
    

    Das verstehe ich nicht, warum wird beim Postfix Operator keine Referenz zurückgegeben. Wenn ich bis jetzt alles richtig gecheckt habe, dann heißt es doch "freies Objekt ohne Referenz --> KOPIE --> Zeitaufwand", "Referenz --> keine KOPIE --> nicht so großer Zeitaufwand"....so mhm??? Also würde ich das so machen:

    #include <iostream>
    
    class foo
    {
    public:
        foo(int nr):m_nr(nr) {}
    
        foo & operator++ ()    // Präfix
        {
            ++m_nr;
            return *this;
        }
    
        const foo & operator++ (int)  // die Postfix-Version bekommt ein int-dummy Parameter
        {                           // um sie von der Präfix-Version unterscheiden zu können
            foo &tmp(*this);
            ++(*this);       // benuzt den Präfix-Operator
            return tmp;
        }
    private:
        int m_nr;
    };
    
    int main()
    {
    
        return 0;
    }
    

    Und was ich noch nicht verstehe warum wird da extra ein "foo tmp" Objekt angelegt, es würde doch reichen wenn man einfach "++(*this)" macht und dieses dann return (der Rückgabetyp muss dann halt eine Referenz sein..schon klar).
    Kann mir nochmal jemand helfen? 😃

    MfG
    Stromberg



  • Du scheinst an der Stelle ein Verständnisproblem mit dem Postfix-Inkrement zu haben. Dieser liefert das Objekt vor der Inkrementierung zurück. Da zu dem Zeitpunkt der Rückgabe aber das Objekt bereits inkrementiert wurde, muss das Objekt vor der Inkrementierung logischerweise eine Kopie sein. Ein Objekt kann nicht gleichzeitig den neuen und alten Wert besitzen 😉

    Und da "tmp" eine lokale Variable innerhalb der Funktion ist, die am Ende der Funktion zerstört wird, kannst Du keine Referenz auf sie zurückgeben. D.h. Du kannst schon, aber das wird nicht das erwartete Ergebnis bringen.



  • Das hat eine ganz einfache Ursache:
    Wenn man a=x++ schreibt, will man an der Stelle des "x++", dass das x erhöht wird, aber man will noch mit dem ursprünglichen Wert weiterarbeiten. Deshalb wird normalerweise bei "x++" intern das x erhöht und ein neues Objekt zurückgegeben, das dem x vor dem Erhöhen entspricht.

    Hier

    const foo & operator++ (int)
    {
        foo &tmp(*this);
        ++(*this);
        return tmp;
    }
    

    ist "tmp" eine Referenz, die das aktuelle Objekt referenziert. Das Objekt wird um eins erhöht und die Referenz zurückgegeben. Das Problem dabei ist, dass dann schon das "erhöhte" Objekt zurückgegeben wird (es wird ja das aktuelle zurückgegeben und "tmp" verweist ja auf "*this").
    Also legt man normalerweise eine Kopie an: foo tmp( *this ); , was ein vollwertiges neues Objekt mit dem Zustand von x ist. Dann erhöht man das richtige x ++(*this) und gibt das Objekt mit dem nicht-erhöhten Zustand zurück return tmp; . Eine Referenz darauf zurückgeben, würde nicht funktionieren, da das neu erzeugte Objekt beim Verlassen der Funktion zerstört wird - die Referenz würde ins Nirvana zeigen.



  • Ah okay, is klar, des hab ich wirklich ma verstanden.



  • MH ne doch nicht ganz, warum verwndet man nur beim postfix operator ein "const"?
    MfG
    Stromberg



  • Siehe mein Codebeispiel auf Seite 2. int verhält sich auch so, also muss du dafür sorgen, dass dein math das selbe Spiel spielt.



  • Noch eine neue Frage. Wieder das Beispiel von dem Link:

    class foo 
    { 
    public: 
        foo(int nr):m_nr(nr) {} 
    
        foo & operator++ ()    // Präfix 
        { 
            ++m_nr; 
            return *this; 
        } 
    
        const foo operator++ (int)  // die Postfix-Version bekommt ein int-dummy Parameter 
        {                           // um sie von der Präfix-Version unterscheiden zu können 
            foo tmp(*this); 
            ++(*this);       // benuzt den Präfix-Operator 
            return tmp; 
        } 
    private: 
        int m_nr; 
    };
    

    Der Postfix Operator nutzt doch den Präfix Operator nä? Wäre es nicht schneller wenn man ihm Postfix Operator einfach auch "++m_nr" reinschreibt, anstatt "++(*this)", sodass nicht extra der Präfix Operator aufgerufen werden muss? Oder ist das total egal?

    MfG
    Stromberg



  • Stromberg schrieb:

    Der Postfix Operator nutzt doch den Präfix Operator nä? Wäre es nicht schneller wenn man ihm Postfix Operator einfach auch "++m_nr" reinschreibt, anstatt "++(*this)", sodass nicht extra der Präfix Operator aufgerufen werden muss? Oder ist das total egal?

    Theoretisch ja, praktisch nein.

    Compiler sind nicht dumm - wenn sie sehen dass ++*this nichts anderes als ein ++n macht, dann optimieren sie das dahingehend.



  • Ah okay, dann kann ich ja dadurch wenigstens den compilier Vorgang schneller machen ^^ 😃



  • Stromberg schrieb:

    Der Postfix Operator nutzt doch den Präfix Operator nä? Wäre es nicht schneller wenn man ihm Postfix Operator einfach auch "++m_nr" reinschreibt, anstatt "++(*this)", sodass nicht extra der Präfix Operator aufgerufen werden muss? Oder ist das total egal?

    Theoretisch könnte es schneller sein, aber bei der Größe wird der Aufruf sowieso inline aufgelöst und dann sind beide Versionen identisch. ABER: Wenn du kompliziertere Klassen hast, wird auch der Code zum Inkrementieren aufwendiger - und dann ist es günstiger, nur eine Stelle anzupassen, als wenn du immer darauf achten müsstest, daß Präfix- und Postfix-Inkrement das selbe machen.


Anmelden zum Antworten