Rückgabewert eines Instanzenzählers


  • Mod

    Das ist nicht direkt eine Optimierung, aber es ist da, um Optimierungen zu ermöglichen und das ist auch gut so und daher kann man es auch nicht ausschalten.

    In C++ gibt es sogenannte Sequenzpunkte. Erst bei erreichen eines Sequenzpunktes ist garantiert, dass alle Nebeneffekte eingetreten sind (oder zumindest, dass sich das Programm so verhält, als ob).

    cout << i << ". " << a.bar() << " / " << b.bar() << endl;
    

    Hier ist ein Sequenzpunkt am Ende der Zeile, aber zwischen a.bar() und b.bar() ist keiner. Daher ist die Reihenfolge in der die Nebeneffekte der Aufrufe auftreten undefiniert (nur dass am Ende der Zeile der Zähler um 2 größer ist). Dies ist auch unter anderem bei Funktionsaufrufen der Fall (eine weitere beliebte Anfängerfalle):

    void foo(int x, int y);
    
    foo(a.bar(), b.bar());  // Ebenfalls undefiniert, in welcher Reihenfolge die bar()s abgearbeitet werden
    

    In sehr schlechten Büchern steht dies manchmal anders beschrieben, dies ist ein sicheres Zeichen, dass man das Buch wegwerfen sollte.

    Ganz besonders aufpassen muss man noch, dass zwischen den Seiten eines Zuweisungsoperators ebenfalls kein Sequenzpunkt ist, d.h. dass ein Ausdruck wie
    i = i++; sogar undefiniertes Verhalten ist (d.h. nicht nur die Reihenfolge ist undefiniert, sondern es darf wirklich alles passieren, das Programm dürfte sogar deinen Goldfisch schwängern).

    Eine gute Faustregel ist, Seiteneffekte eher zu vermeiden, das hat auch an anderer Stelle große Vorteile, weil insgesamt alles viel übersichtlicher wird. Manchmal lässt es sich aber nicht vermeiden, wie zum Beispiel eben bei einem Instanzenzähler. Wobei dein Programm derzeit nicht viel mit einem Instanzenzähler zu tun hat, sondern die Anzahl der bar()-Aufrufe zählt.



  • SeppJ schrieb:

    aber zwischen a.bar() und b.bar() ist keiner.

    Das Zurückkehren aus einer Funktion ist doch auch ein Sequenzpunkt, oder nicht? Eine der beiden Funktionen wird zuerst abgearbeitet, dann ist doch alles ok. Ich sehe da jetzt kein Problem, dass es mit den Werten der Variablen Probleme geben könnte.

    edit: Ich glaube, wir meinen dasselbe und reden dennoch aneinander vorbei, SeppJ.


  • Mod

    Gugelmoser schrieb:

    SeppJ schrieb:

    aber zwischen a.bar() und b.bar() ist keiner.

    Das Zurückkehren aus einer Funktion ist doch auch ein Sequenzpunkt, oder nicht? Eine der beiden Funktionen wird zuerst abgearbeitet, dann ist doch alles ok.

    Ja, aber ich wollte es nicht überkompliziert darstellen. Falls es durch die Vereinfachung zu Verwirrung kam, bitte ich, dies zu entschuldigen.



  • Wobei dein Programm derzeit nicht viel mit einem Instanzenzähler zu tun hat, sondern die Anzahl der bar()-Aufrufe zählt.

    Das stimmt natürlich, absolut richtig...

    OK, ich denke, jetzt ist mir das alles klarer geworden.

    Daher allen vielen Dank für die Erklärungen!

    Herzliche Grüße,
    Antrinsic



  • Wieso ist i = i++; denn undefiniert? Ich verstehe, dass i entweder dem alten oder neuen i entsprechen dürfte, aber wieso auch etwas darüber hinaus?

    Und wenn ich z.B. einen Ausdruck habe wie:

    if(ptr && ptr->whatever())
    

    ist das dann auch undefiniert oder bildet hier das && einen Sequenzpunkt? Kenne die Terminologie überhaupt nicht.



  • Eisflamme schrieb:

    Und wenn ich z.B. einen Ausdruck habe wie:

    if(ptr && ptr->whatever())
    

    ist das dann auch undefiniert oder bildet hier das && einen Sequenzpunkt? Kenne die Terminologie überhaupt nicht.

    Das wird durch Short Circuit Evaluation meistens so verlaufen wie du willst.

    Wieso ist i = i++; denn undefiniert? Ich verstehe, dass i entweder dem alten oder neuen i entsprechen dürfte, aber wieso auch etwas darüber hinaus?
    

    Undefiniert ist undefiniert. Wenn der Standard implizit aussagt, es ist undefiniert, dann issasso. 🙂



  • Eisflamme schrieb:

    Wieso ist i = i++; denn undefiniert? Ich verstehe, dass i entweder dem alten oder neuen i entsprechen dürfte, aber wieso auch etwas darüber hinaus?

    Weil dasselbe skalare Objekt zweimal modifiziert wird. Steht so im Standard. (Sogar explizit, @Sone)

    bildet hier das && einen Sequenzpunkt?

    Ja. Genauso wie ||, ?: und der Kommaoperator. Einfach mal ein bisschen im Standard schmökern ... allerdings im alten Standard. In C++11 ist die Terminologie anscheinend komplett anders.



  • Meistens? Das klingt nicht sehr sicher.

    i = i++; versteh ich jetzt. Dass der Standard es als undefiniert definiert (bzw. eben nicht definiert, was dasselbe wie undefiniert ist), dann finde ich jedoch diesen seltsam. Wenn ich durch einen solchen Fehler plötzlich einen schwangeren Goldfisch hätte, würde mich das durchaus irritieren, das macht C++ gefährlicher als bisher angenommen.

    Bashar: Okay, danke. 🙂



  • Bashar schrieb:

    In C++11 ist die Terminologie anscheinend komplett anders.

    Das interessiert mich jetzt. Schreib gleich, was ich finde.



  • Hier stehts:

    N3337 Paragraph 5.14 Klausel 1 schrieb:

    The && operator groups left-to-right. The operands are both contextually converted to type bool (Clause 4).
    The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right
    evaluation: the second operand is not evaluated if the first operand is false.

    Das nennt sich Short Circuit Evaluation.


  • Mod

    Bashar schrieb:

    In C++11 ist die Terminologie anscheinend komplett anders.

    Und viel einfacher.
    Das Grundregeln finden sich in 1.9/13-15
    Als Folge sind einige Konstrukte, die im alten Standard undefiniert blieben, jetzt bloss noch unspezifiziert.



  • Sone schrieb:

    Das nennt sich Short Circuit Evaluation.

    Und hat mit dem Thema überhaupt nichts zu tun. Du hättest nur Absatz 2 statt 1 zitieren müssen, da geht es um sequencing

    If the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression.



  • Bashar schrieb:

    Sone schrieb:

    Das nennt sich Short Circuit Evaluation.

    Und hat mit dem Thema überhaupt nichts zu tun. Du hättest nur Absatz 2 statt 1 zitieren müssen, da geht es um sequencing

    If the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression.

    Edit: Nein, hier wird es anders garantiert. Hast Recht.


Anmelden zum Antworten