2016-03-21 9 views
4

Ich rufe die faktorielle Funktion auf, die auf folgende Weise durch Referenz definiert wird.Warum wird der Code beim Ändern der Reihenfolge in der Zuweisungsanweisung anders implementiert?

Wenn ich den Wert 5 übergeben, gibt es den Wert 1 zurück, wie ich erwartet hatte. Aber wenn ich die Fakultäts-Funktion in der folgenden Art und Weise definieren gibt es die Fakultät von 5, die 120 ist

int factorial(int &n) { 
    n--; 
    if (n>0) return (n+1)*factorial(n); 
    else return 1; 
} 

Ich vermuten, dass der Ausdruck in linearer Reihenfolge ausgewertet wird und wenn eine Funktion in dem Ausdruck all Werte aufgerufen von lokalen Variablen und den Komponentenausdrücken, die bisher im ursprünglichen Ausdruck ausgewertet wurden, werden gespeichert, und wenn die Funktion die Steuerung zurück an den Aufrufer zurückgibt, werden diese Werte, die beibehalten werden, bei der Berechnung des Ausdrucks und nicht ihrer modifizierten Werte verwendet.

Ist meine Hypothese korrekt? Erleuchte mich bitte.

+0

Leider habe ich einen Tippfehler gemacht n und nicht n-1 –

+0

Nach Korrektur Ihrer Tippfehler sein sollte, ist es klar, dass n doesn‘ t seinen Wert beibehalten, weil er als Referenz übergeben wird. – stefaanv

+2

@NathanOliver Sie verwendeten dasselbe n für beide Funktionen. Ist es nicht wichtig? –

Antwort

10

Ich vermuten, dass der Ausdruck in linearer Reihenfolge ausgewertet wird [...]

Ja und nein. Die Reihenfolge der Auswertung erfolgt typischerweise in linearer Reihenfolge (entweder zuerst zum letzten oder vom letzten zum ersten), ist aber nicht spezifiziert. Wenn Sie factorial(n)*(n+1) schreiben, darf der Compiler zuerst (n+1) oder factorial(n) zuerst auswerten. Verschiedene Compiler werden es anders machen. Außerdem können verschiedene Versionen des gleichen Compilers sogar die Reihenfolge ändern, auf die Sie sich nicht verlassen sollten. Die standardese ist in [intro.execution]:

Soweit nicht anders angegeben, Auswertungen von Operanden von einzelnen Betreibern und der Unterausdrücke einzelnen Ausdrücke unsequenced sind. [...] Wenn ein Nebeneffekt auf ein Skalarobjekt relativ zu einem anderen Nebeneffekt desselben Skalarobjekts oder einer Wertberechnung unter Verwendung des Werts desselben Skalarobjekts nicht sequenziert wird und sie nicht gleichzeitig auftreten (1.10), Das Verhalten ist nicht definiert.

(Ausnahmen sind Dinge wie &&, ||, , und ?:)

In diesem Fall können Sie ganz einfach in der Größenordnung Abhängigkeit von nur Entfernen des Verweises vollständig nicht darauf angewiesen:

int factorial(int n) { 
    if (n>0) return factorial(n-1)*(n); 
    else return 1; 
} 

Jetzt factorial(n-1) * n und n * factorial(n-1), unabhängig von der Reihenfolge, in der sie ausgewertet werden, funktionieren beide und geben Ihnen die gleiche richtige Antwort. Dies hat auch den zusätzlichen Vorteil, dass niemand factorial erwarten würde, um tatsächlich ihr Argument ändern trotzdem:

int i = 6; 
int f = factorial(i); 
// now i is 1?? 
+0

Was ich mit linearer Reihenfolge meine, ist, dass, wenn der Ausdruck links-assoziativ ausgewertet wird und wenn ein Ausdruck auftritt, der eine Funktion aufruft, die Werte, die ausgewertet wurden, nach Rückkehr der Kontrolle erhalten bleiben. –

+0

@SiddharthJoshi Linksassoziativ bedeutet, dass in 'x * y * z'' x * y' zuerst passiert und dann 'r * z' als zweites passiert. Es bestimmt nicht die Reihenfolge, in der 'x', 'y' und 'z' ausgewertet werden. – Barry

+0

Was ich Sie fragen möchte, ist, dass, wenn an Stelle von y gab es einen Ausdruck sagen "Summe (x, z)" und Summe ändert die Variablen dann, was passiert mit dem Wert dieses Ausdrucks. Wird der ursprüngliche Wert von "x" für die Berechnung von "x * y * z" verwendet oder werden die geänderten Werte verwendet? –

Verwandte Themen