Wenn wir drei Funktionen (foo, bar und baz) haben, die so zusammengesetzt sind …
foo(bar(), baz())
Gibt es eine Garantie durch den C++-Standard, dass bar vor baz ausgewertet wird?
Wenn wir drei Funktionen (foo, bar und baz) haben, die so zusammengesetzt sind …
foo(bar(), baz())
Gibt es eine Garantie durch den C++-Standard, dass bar vor baz ausgewertet wird?
Eli Bendersky
Nein, eine solche Garantie gibt es nicht. Es ist gemäß dem C++-Standard nicht spezifiziert.
Bjarne Stroustrup sagt es auch explizit in “The C++ Programming Language”, 3. Auflage, Abschnitt 6.2.2, mit einigen Begründungen:
Besserer Code kann generiert werden, wenn die Reihenfolge der Ausdrucksauswertung nicht eingeschränkt ist
Obwohl sich dies technisch auf einen früheren Teil desselben Abschnitts bezieht, der besagt, dass die Reihenfolge der Auswertung von Teilen eines Ausdrucks ebenfalls nicht spezifiziert ist, dh
int x = f(2) + g(3); // unspecified whether f() or g() is called first
Ja, aber besserer Code könnte WRITTEN (= sauberer) sein, wenn die Auswertungsreihenfolge der Ausdrücke STRICT wäre, was im Allgemeinen viel wichtiger ist als die Codegenerierung. Siehe dieses Beispiel: stackoverflow.com/questions/43612592/… Also, Stroustrup.
– Bill Kotsias
25. April 2017 um 13:57 Uhr
Wenn es auf die Bestellung ankommt, können Sie die Sequenzierung selbst vornehmen. Andernfalls würden immer Kosten für etwas entstehen, das nicht immer (selten?) wichtig ist. Ich denke, dass die Richtlinie, nicht für das zu bezahlen, was Sie nicht verwenden, das einzige ist, dem die meisten C++-Programmierer zustimmen.
– tweej
2. Dezember 2017 um 9:53 Uhr
Sollte es nicht “nicht spezifiziertes Verhalten” statt “undefiniert” heißen?
– Gute Taten
6. Januar 2018 um 19:38 Uhr
@GoodDeeds Vor C++17, undefiniertes Verhalten, wenn die Funktionen Seiteneffekte am selben Speicherort verursachen. Nach C++17 ist es nicht spezifiziert.
– Passant
22. Juni 2018 um 16:53 Uhr
@ChrisDodd, der eine akzeptierte Antwort aufgrund der Verwendung des Wortes “undefiniert” vs. “nicht spezifiziert” ablehnt, fühlt sich für mich wie böswillige Pedanterie an … Ich habe nicht gesagt, dass dies “undefiniertes Verhalten” ist, und ansonsten scheinen “undefiniert” und “nicht spezifiziert” zu sein gleichbedeutend? In jedem Fall wäre es produktiver gewesen, eine Änderung der Antwort vorzuschlagen, um dies zu diskutieren
– Eli Bendersky
20. Juli 2018 um 13:19 Uhr
Daniel Trebien
Von [5.2.2] Funktionsaufruf,
Die Reihenfolge der Bewertung der Argumente ist nicht festgelegt. Alle Seiteneffekte der Auswertung von Argumentausdrücken werden wirksam, bevor die Funktion eingegeben wird.
Daher gibt es dafür keine Garantie bar()
wird vorher laufen baz()
nur das bar()
und baz()
wird vorher angerufen foo
.
Beachten Sie auch von [5] Ausdrücke, die:
außer wo vermerkt [e.g. special rules for
&&
and||
]die Reihenfolge der Auswertung von Operanden einzelner Operatoren und Unterausdrücke einzelner Ausdrücke sowie die Reihenfolge, in der Seiteneffekte auftreten, ist nicht festgelegt.
also selbst wenn Sie fragen würden, ob bar()
wird vorher laufen baz()
in foo(bar() + baz())
die Reihenfolge ist noch nicht festgelegt.
Ein Beispiel für einen “besonderen Hinweis” von [5.14] Logischer UND-Operator: „Anders &
, &&
garantiert Links-nach-rechts-Auswertung: Der zweite Operand wird nicht ausgewertet, wenn der erste Operand es ist false
.”
– Daniel Trebbien
29. Mai 2010 um 12:31 Uhr
Es gibt keine festgelegte Reihenfolge für bar() und baz() – das einzige, was der Standard sagt, ist, dass sie beide ausgewertet werden, bevor foo() aufgerufen wird. Aus dem C++-Standard, Abschnitt 5.2.2/8:
Die Reihenfolge der Bewertung der Argumente ist nicht festgelegt.
Die Tatsache, dass sie vor foo() ausgewertet werden, ist zumindest etwas beruhigend.
– Bill Kotsias
25. April 2017 um 13:58 Uhr
@BillKotsias Der Standard besagt auch, dass sich Funktionsaufrufe nicht überlappen dürfen (dh eine Implementierung kann Zeile 1 von nicht ausführen bar
dann Zeile 1 von baz
dann Zeile 2 von bar
, etc.), was auch schön ist. 🙂
– Melpomen
31. Juli 2019 um 21:04 Uhr
C++17 gibt die Auswertungsreihenfolge für Operatoren an, die bis C++17 nicht angegeben war. Siehe die Frage Was sind die von C++17 eingeführten Garantien für die Bewertungsreihenfolge? Aber achte auf deinen Gesichtsausdruck
foo(bar(), baz())
hat noch nicht spezifizierte Auswertungsreihenfolge.
In C++11 findet sich der entsprechende Text in 8.3.6 Standardargumente/9 (Hervorhebung von mir)
Standardargumente werden bei jedem Aufruf der Funktion ausgewertet. Die Reihenfolge der Auswertung von Funktionsargumenten ist nicht festgelegt. Folglich dürfen Parameter einer Funktion nicht in einem Standardargument verwendet werden, auch wenn sie nicht ausgewertet werden.
Dieselbe Wortwahl wird auch vom C++14-Standard verwendet und ist unter zu finden der gleiche Abschnitt.
Gelehrter Programmierer
Wie andere bereits betont haben, gibt die Norm keine Anleitung zur Bewertungsreihenfolge für dieses spezielle Szenario. Diese Auswertungsreihenfolge wird dann dem Compiler überlassen, und der Compiler hat möglicherweise eine Garantie.
Es ist wichtig, sich daran zu erinnern, dass der C++-Standard eigentlich eine Sprache ist, um einen Compiler anzuweisen, Assembly-/Maschinencode zu erstellen. Der Standard ist nur ein Teil der Gleichung. Wenn der Standard mehrdeutig ist oder eine spezifische Implementierung definiert ist, sollten Sie sich an den Compiler wenden und verstehen, wie er C++-Anweisungen in echte Maschinensprache übersetzt.
Wenn also die Reihenfolge der Auswertung eine Voraussetzung oder zumindest wichtig ist und Cross-Compiler-Kompatibilität keine Voraussetzung ist, untersuchen Sie, wie Ihr Compiler dies letztendlich zusammenfügt, Ihre Antwort könnte letztendlich dort liegen. Beachten Sie, dass der Compiler seine Methodik in Zukunft ändern könnte