In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?



  • Hallo zusammen,

    ich habe Code ähnlich zu diesem hier:

    Foo bar  {  getInput1(), getInput2() };
    

    die beiden Methoden lesen wie der Name sagt Inputs von der Konsole ein.

    Mit gcc / clang bzw. auf Linux / Mac Os klappt alles wunderbar:

    > Gebe Input 1 ein: 
    > Gebe Input 2 ein: 
    

    Mit MSVC bzw. Windows kommt dagegen

    > Gebe Input 2 ein: 
    > Gebe Input 1 ein: 
    
    getInput1(); 
    getInput2();
    

    klappt auf allen Plattformen wie erwartet.

    Ist meine Annahme falsch, dass Argumente eines Konstruktors von links nach rechts ausgewertet werden? Wie definiert das der Standard?



  • Ich kann meine Antwort wohl selbst geben, bin drauf gestoßen denke ich:

    https://en.cppreference.com/w/cpp/language/eval_order

    Wieso? Wer hat sich das ausgedacht?



  • In den Normungsausschüssen sitzen halt Vertreter der Industrie, und jeder Hersteller will halt sein eigenes System schützen. Deshalb erfolgte nie eine Festlegung in welcher Reihenfolge das geschehen soll. Man kann in diesem Fall das leicht umgehen, in dem man nicht den Komma-Operator nutzt. Korrektur: Genau an dieser Stelle wird der Komma-Operator gerade nicht genutzt, und deshalb ist die Reihenfolge auch nicht wohl definiert. Wenn man den Komma-Operator nutzen wollte, müsste man ihn in einer extra Klammer verwenden. Die Initialisierungsreihenfolge im Konstruktor folgt der Definition der Member (1) und diese Version sollte man bevorzugen.

    class Foo {
        std::string a_;
        std::string b_;
    public:
        // hier erfolgt die Konstruktion in der Reihenfolge der Deklaration, d.h. zuerst a_ dann b_.
        Foo () : a_(getInput1()), b_(getInput2()) {} // (1)
        // oder alternativ die Reihenfolge durch Abfolge festlegen
        Foo () { // (2)
            a_ = getInput1();
            b_ = getInput2();
        }
    };
    


  • @john-0 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Deshalb erfolgte nie eine Festlegung in welcher Reihenfolge das geschehen soll. Man kann in diesem Fall das leicht umgehen, in dem man nicht den Komma-Operator nutzt.

    class Foo {
        std::string a_;
        std::string b_;
    public:
        // [...]
        // so ist die Reihenfolge undefiniert
        Foo () {
            a_ = getInput1(), b_ = getInput2();
        }
    };
    

    Ist das wahr, dass die Reihenfolge undefiniert ist? Der Kommaoperator ist doch was anderes als das Komma, das die Funktionsaufrufargumente trennt.



  • Nein, die Reihenfolge beim Sequenzoperator ist wohldefiniert (von links nach rechts).

    Und nur bei der Auswertung von Funktionsparametern (bzw. bei Operatoren) ist die Reihenfolge nicht festgelegt (unspecified).



  • Bedeutet das echt ihr schreibt immer sowas:

    auto arg1 = func1(); 
    auto arg2 = func2(); 
    Foo bar { arg1, arg2 };
    

    Das finde ich ja wirklich fürchterlich 😅

    Also manchmal / oft wird vlt. auch die Reihenfolge irrelevant sein, weswegen man das verkürzt schreiben kan. Aber immer drüber nachzudenken: Welche Seiteneffekte gibt es? Könnte da nicht doch was reihenfolgen abhängig sein? -> Sehr fehlerbehaftet imo.

    Hier ist übrigens die / eine Begründung: https://isocpp.org/blog/2016/08/quick-q-why-doesnt-cpp-have-a-specified-order-for-evaluating-function-argum.
    Natürlich Performance ...

    Ich würde mir manchmal wünschen, dass ich sagen kann: Ich verzichte auf das bisschen Performance, aber dafür soll sich alles etwas intuitiver verhalten 😃

    Ich habe mal kurz nachgeschaut: Java und Python haben Left-to-Right garantiert, während z.B. in Rust es auch unklar ist (oder zumindest wahr ... es gibt da längere Diskussionen für Language Proposals und ich habe sie mir nicht komplett durchgelesen)



  • @Leon0402 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Welche Seiteneffekte gibt es? Könnte da nicht doch was reihenfolgen abhängig sein?

    Dann hast du etwas falsch gemacht. Auch bei dir gibt es keine Abhängigkeit.

    Wenn du auf Performance verzichten willst, ist C++ vielleicht die falsche Sprache.



  • @manni66 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    @Leon0402 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Welche Seiteneffekte gibt es? Könnte da nicht doch was reihenfolgen abhängig sein?

    Dann hast du etwas falsch gemacht. Auch bei dir gibt es keine Abhängigkeit.

    Wenn du auf Performance verzichten willst, ist C++ vielleicht die falsche Sprache.

    Deine Aussage verstehe ich nicht so ganz. In dem Fall soll eine Eingabe vor der anderen erfolgen, das würde ich schon als Abhängigkeit bezeichnen?

    Ich möchte nicht auf Performance verzichten, Nur vlt. nicht um jeden Preis Mikrooptimierungen haben, um dafür dann schwer lesbaren Code oder schwierige Bugs zu haben. Ich kann natürlich jetzt nicht 100% beurteilen wie viel Performance Gewinn es tatsächlich macht, dass man die Reihenfolge hier nicht spezifiziert.
    Ich denke es ist durchaus legitim, dass man mehr Kontrolle und Performance als bei z.B. Java haben möchte, aber durchaus sich bewusst ist, dass man hier aktuell für einen PC entwickelt und nicht für nen 8-Bit Mikokontroller, oder?



  • @Leon0402 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Ich denke es ist durchaus legitim, dass man mehr Kontrolle und Performance als bei z.B. Java haben möchte, aber durchaus sich bewusst ist, dass man hier aktuell für einen PC entwickelt und nicht für nen 8-Bit Mikokontroller, oder?

    Und dann gibt es mehrere C++ Dialekte?

    würde ich schon als Abhängigkeit bezeichnen?

    Es gefällt dir nicht. Es führt aber nicht zu einem Fehler.



  • @manni66 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Es gefällt dir nicht. Es führt aber nicht zu einem Fehler.

    Also nur was der Compiler anmeckert ist ein Fehler, oder wie darf ich das verstehen? Wenn etwas logisch nicht so abläuft wie ich das vor hatte, würde ich das schon auch als einen Fehler bezeichnen.

    @manni66 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Und dann gibt es mehrere C++ Dialekte?

    ich würde eher sagen mehrere Optimierungsstufen. Gibt es ja jetzt schon. Nur das sie ja (soweit ich weiß) nicht standardisiert sind, sondern compiler abhängig.



  • @Leon0402 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Wenn etwas logisch nicht so abläuft wie ich das vor hatte, würde ich das schon auch als einen Fehler bezeichnen.

    Dort ist kein logischer Fehler.

    Und wenn es tatsächlich so wäre, dass Parameter eines Konstruktors in der „richtigen“ Reihenfolge stehen müssen, damit dein Programm keinen logischen Fehler hat, trifft ein, was ich vorher sagte: du hast etwas falsch gemacht.

    ich würde eher sagen mehrere Optimierungsstufen. Gibt es ja jetzt schon. Nur das sie ja (soweit ich weiß) nicht standardisiert sind, sondern compiler abhängig.

    Die machen aber ein korrektes Programm nicht zu einem fehlerhaften, wie du es vorschlägst.



  • @Th69 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    Ich denke es ist durchaus legitim, dass man mehr Kontrolle und Performance als bei z.B. Java haben möchte, aber durchaus sich bewusst ist, dass man hier aktuell für einen PC entwickelt und nicht für nen 8-Bit Mikokontroller, oder?

    Ich denke, das kommt eher aus der HPC-Ecke, weil da so geringe Performanzunterschiede sich am Ende zu starken Laufzeitunterschieden aufsummieren.



  • @john-0: Das ist nicht mein Zitat, sondern vom OP 😉

    (Kann nichts dafür, daß dein Name nicht korrekt als "*john 0" gezeigt wird, das macht der Foreneditor so bei Auswahl mittels @).



  • @Th69 sagte in In welcher Reihenfolge werden die Argument Übergaben eines Konstruktors aufgerufen?:

    (Kann nichts dafür, daß dein Name nicht korrekt als "*john 0" gezeigt wird, das macht der Foreneditor so bei Auswahl mittels @).

    Entschuldigung für den Fehler.
    P.S. Der Forennamen wurde irgend wann bei der Umstellung konvertiert, früher war das mal ~john. Nur john war damals schon belegt.


Log in to reply