Verständnisfrage zu C++11 Sequencing



  • Guten Abend,

    nachdem ich jetzt mehrere Artikel zu dem o.g. Thema gelesen hab', hab ich glaub ich verstanden, warum Beispiel 1 eine Warnung ausgibt und Beispiel 2 nicht. Ich möchte aber nochmal auf Nummer sicher gehen und bei euch nachfragen, ob ich das richtig verstanden habe:
    In Beispiel 1 ist beim Aufruf der Funktion "test" nicht garantiert, in welcher Reihenfolge die Werte zugewiesen werden und daher könnte theoretisch auch statt "a=1, b=2, c=3" sowas rauskommen wie "a=3, b=1, c=2", obwohl es das in diesem Beispiel anscheinend nicht tut (siehe Ausgabe) ?
    In Beispiel 2 hat die Zuweisungsreihenfolge keinen Einfluss auf den Wert "i" bzw. die einzelnen Werte, die übergeben werden sollen, daher keine Warnung?

    Beispiel 1:

    #include <iostream>
    using namespace std;
    
    void test (int a, int b, int c)
    {
          cout << "a:" << a << " b:" << b << " c:" << c << endl;
    }
    
    int main()
    {
        int i = 0;
        test (++i, ++i, ++i);   //warning: multiple unsequenced modifications to 'i' [-Wunsequenced]
        
        return 0;
    }
    
    Ausgabe: 
    a:1 b:2 c:3
    
    

    Beispiel 2 (wie Bsp1, nur Zeile 12 durch diese hier ersetzt):

        test (i+1, i+2, i+3);   //keine Warnung
    
    Ausgabe: 
    a:1 b:2 c:3
    

    Wenn dem so ist, gibt es denn eine Möglichkeit auf die Variante in Bsp 2 zu verzichten und ohne diese "magic numbers" auszukommen? Wenn ich nämlich noch mehr Werte habe, die ich an die Funktion übergeben möchte, die ich später evtl auch nochmal zwischendrin ergänzen möchte, möcht ich möglichst auf das manuelle hochzählen (i+1, i+2 etc.) verzichten, v.a. weil es beim späteren Bearbeiten auch fehleranfällig ist.



  • a = ++i;
    b = ++i;
    c = ++i;
    test(a,b,c);
    


  • Dein zweites Beispiel modifiziert i ja nicht, daher ist es egal. Das erste verändert allerdings i. Wie genau da der Ablauf ist (ob dieser überhaupt festegelegr ist, weiß ich allerdings nicht).
    Generell gilt ja, dass man Seiteneffekte vermeiden soll. Ich meine irgendwo gelesen zu haben, dass man auch vermeiden sollte, eine Variable mehrmals in einer Anweisung zu verändern wie in Beispiel 1 geschehen (sogar gleich dreimal).



  • Danke für die Hinweise! Ich dachte ich könnte mir die Variablen-Deklaration/-Zuweisung vorher sparen und die Werte direkt im Funktionsaufruf ermitteln, denn man sollte ja immer so wenig wie möglich Code schreiben, um es übersichtlich zu halten, aber manchmal muss wohl doch etwas mehr Code her, um unerwünschte Nebeneffekte zu vermeiden...



  • Von dem Gedanken, dass wenig Code == übersichtlicher Code ist, solltest du schnell wegkommem.
    Zu übersichtlichen Code gehört es Code richtig in Funktionen zu gliedern, sinnvoll zu abstrahieren, zu kommentieren.

    Ja manchmal sind verschachtelte Aufrufe besser lesbar als lauter tmp Variablen, aber auch nur bis zu einem bestimmten Grad. Hier muss man einfach ein geigneted Mittelmaß finden.
    Seiteneffekte sind grundsätzlich schwierig, da entstehen auch die Fehler, die man nicht so leicht findet. Ich will es aber hier nicht also nogo bezeichen ... man kann damit schon ganz sinnvolle while schleifen schreiben, aber eben als Orientierung eher vermeiden.

    Man könnte das ganze übrigens auch so machen.

    test(i + 1, i + 2, i + 3);
    i += 3;
    

    Hier spart man sich auch die lokalen Variablen und es ist auch meiner Meinung nach schneller erkennbar, welche Werte a,b und c tatsächlich haben.



  • @Leon0402 sagte in Verständnisfrage zu C++11 Sequencing:

    Wie genau da der Ablauf ist (ob dieser überhaupt festegelegr ist, weiß ich allerdings nicht).

    Ich hab' zwar jetzt kein Standard-Zitat bei der Hand, aber die evaluation von Funktionsparametern untereinander is unsequenced. Die einzige garantie ist die, daß die Auswertung sequenced-before dem ersten Statement des jeweiligen Funktionsbodies ist.




Log in to reply