Fragen Aktuellen- und Formalen-Paramtetern
-
Ein Aktueller-Parameter ist ein Parameter der vom Aufrufer zur Verfügung gestellt wird.
Ein Formaler-Parameter ist der Parameter innerhalb der Funktion den man verwenden kann. Sagt man zum Formalen-Parameter nicht auch Lokaler-Parameter?
Ausserdem werden alle Parameter einer Funktion in C++ standardmässig von rechts nach links (cdecl) abgearbeitet.
Die MSDN sagt:Microsoft's MSDN schrieb:
All actual arguments (those supplied by the caller) are evaluated. There is no implied order in which these arguments are evaluated, but all arguments are evaluated and all side effects completed prior to entry to the function.
Wie jetzt.. entweder oder?
-
DeepCopy schrieb:
Ein Aktueller-Parameter ist ein Parameter der vom Aufrufer zur Verfügung gestellt wird.
Ein Formaler-Parameter ist der Parameter innerhalb der Funktion den man verwenden kann. Sagt man zum Formalen-Parameter nicht auch Lokaler-Parameter?
Es ist im allgemeiner bequemer, zwischen Argument (=tatsächlicher Parameter) und Parameter (=formaler Parameter) zu unterscheiden.
DeepCopy schrieb:
Ausserdem werden alle Parameter einer Funktion in C++ standardmässig von rechts nach links (cdecl) abgearbeitet.
Was ist abarbeiten? Die erwähnte Aufrufkonvention spezifiziert lediglich eine bestimmte Reihenfolge, in der die Funktionsparameter auf dem Stack abgelegt werden, damit ist keine Aussage über die Reihenfolge ihrer Initialisierung getroffen.
Im Übrigen geht das über Standard C++ hinaus - Aufrufkonventionen sind naturgemäß implementationsabhängig. Der Standard spezifiziert keinerlei Reihenfolge zwischen der Auswertung von Funktionsargumenten - zudem befinden sich dazwischen keine sequence points.
-
Dann habe das von Microsoft wohl falsch verstanden!
camper schrieb:
eine bestimmte Reihenfolge, in der die Funktionsparameter auf dem Stack abgelegt werden
Danke, genau das meinte ich mit abarbeiten:
push c; push b; push a; sub esp 12; call "adresse_foo()" add esp 12; ...
camper schrieb:
zudem befinden sich dazwischen keine sequence points.
Was genau meinst du damit ?
-
DeepCopy schrieb:
camper schrieb:
zudem befinden sich dazwischen keine sequence points.
Was genau meinst du damit ?
genau das. Befindet sich ein Sequenzpunkt zwischen zwei Ausdrücken a und b, so ist garantiert, dass jede Änderung von Objekten, die durch die Auswertung von a bedingt sind, abgeschlossen wurden, bevor die Auswertung von b stattfindet (jedenfalls insoweit die Auswertung von b auf diese Objekte zugreift).
Betrachtevoid f(int,int); int inc(int& x) { return ++x; } int a = 0; ++a, ++a; // (1) Ergebnis: a == 2 int v = 0; ++b + ++b; // (2) UB int c = 0; f( ++c, ++c ); // (3) UB int d = 0; f( inc(d), d ); // (4) unspezifiziert: entweder f(1,1) oder f(1,0)
Der Kommaoperator stellt einen Sequenzpunkt zischen den beiden Operanden dar, mithin hat a sicher den Wert 1, bevor die Auswertung der rechten Seite beginnt.
Im 2. Fall besteht keine solche Garantie - wird nun ein Objekt mehrfach verändert wie in Fall 2 und befindet sich dazwischen kein Sequenzpunkt, resultiert daraus undefiniertes Verhalten.
Gleiches gilt für Fall 3.
Fall 4 wiederum ist nur unspezifiert, denn am Beginn und Ende jedes Funktionsaufrufes (also nach erfolgter Initialisierung aller Funktionsparameter, sowie beim Verlassen nach Initialiserung des Funktionsergebnisses und der Zerstörung lokaler Variablen) befindet sich jeweils ein Sequenzpunkt.
Die Unbestimmtheit der Auswertung betrifft auch Teilausdrücke:class X; void sink(auto_ptr<X> a,auto_ptr<X> b); sink(auto_ptr<X>(new X(...)),auto_ptr<X>(new X(...));
Trotz der Verwendung von auto_ptr haben wir es hier mit einem potentiellen Leck zu tun:
nachdem das erste X-Objekt erfolgreich angefordert und initialisiert wurde, ist nicht garantiert, dass der resultierende rohe Zeiger sogleich zur Initialiserung des auto_ptr benutzt wird, es könnte stattdessen erst das zweite new ausgeführt werden. Schlägt dieses 2. new nun fehl (exception), wird das zuerst angeforderte Objekt nicht wieder vernichtet werden.