2012-03-26 18 views
2

Was ist der Unterschied zwischen diesen?Unterschied zwischen den Funktionstypen

MyType myFunction(); 

MyType t = myFunction(); 

UND

MyType &myFunction(); 

MyType t = myFunction(); 

UND

const MyType &myFunction(); 

MyType t = myFunction(); 

Was hinter den Kulissen vor sich geht?

Antwort

3

In den drei Fällen, die zweite Zeile ist gemeinsam:

MyType t = myFunction(); 

Diese Linie das Ergebnis bekommt myFunction aufrufen und verwendet es, um copy-Konstrukt ein neues Element der MyTypet genannt.

Nun zu den Unterschieden. Im ersten Fall geben Sie nach Wert zurück, was bedeutet, dass der Compiler (semantisch) eine Kopie des Objekts erstellen wird, das sich in der return-Anweisung innerhalb myFunction befindet, und diese Kopie dann als Quelle für die Kopierkonstruktion von t verwenden. Der Compiler wird höchstwahrscheinlich die Kopien (mindestens die zweite) kopieren. In den anderen beiden Fällen geben die Funktionen Referenzen an ein anderes Objekt zurück. Wenn es sich bei den Objekten um Einheimische handelt, handelt es sich um undefiniertes Verhalten. Der Unterschied zwischen den beiden besteht darin, ob der zurückgegebene Verweis verwendet werden kann, um das referenzierte Objekt zu ändern oder nicht, und dies könnte sich darauf auswirken, welcher Copy-Konstruktor verwendet wird oder ob es überhaupt verwendet werden kann. Beachten Sie, dass das Objekt, von dem Sie die Referenz erhalten, den Funktionsaufruf überleben muss, oder Sie werden ein undefiniertes Verhalten verursachen.

// an example where it matters: 
typedef std::auto_ptr<int> MyType; 
MyType t = myFunction(); 

std::auto_ptr Weil die rechte Seite auf Zuweisung ändert, wird der vorherige Code nur funktionieren, wenn der zurückgegebene Bezug nicht-const ist.

Luchian weist darauf hin, dass die Rückgabe einer Referenz wird höchstwahrscheinlich undefiniert Verhalten sein, also wann wäre es nicht? Wenn das Objekt, von dem die Referenz erhalten wurde, die Verwendung der Referenz überlebt.Das ist der Grundbaustein des Meyers Singletons:

// an example where returning a reference is correct 
MyType & myFunction() { 
    static MyType instance; // Note static storage duration! 
    return instance; 
} 

Oder jede Ebene accessor, die einen Verweis auf ein Unterobjekt zurückgibt. Einige der häufigsten Fälle sind operator[] in Containern (sie kopieren normalerweise nicht den Wert, sondern geben einen Verweis auf die gespeicherten Daten zurück).

Aber es ist wahr, dass Funktionen oft nicht statisch gelebte Objekte, sondern Einheimische zurückgeben.

+0

Neben dem Meyers-Singleton (das aus verschiedenen Gründen keine universelle Adhäsion hat) könnten Sie Site-Funktionen wie die '[]' -Operatoren in 'std :: vector' und' std :: map' verwenden. Sie sind wahrscheinlich häufigere Beispiele dafür, wo Referenzen für Rückgabewerte verwendet werden. –

+0

@JamesKanze: Richtig, es gibt viele * Accessoren * in Klassen, die Referenzen zurückgeben sollten. Ich habe versucht, die Antwort auf freie Funktionen zu beschränken, so wie es bei der Frage der Fall zu sein scheint. Aktualisiert die Antwort, um dieses spezielle Beispiel zu enthalten. Vielen Dank. –

1

Ich nehme an, das sind freie Funktionen.

MyType myFunction(); 
MyType t = myFunction(); 

gibt ein Objekt MyType nach Wert zurück. Theoretisch wird das Objekt, das innerhalb myFunction erstellt wird, bei der Rückkehr kopiert. In der Praxis wird RVO höchstwahrscheinlich auftreten.

MyType &myFunction(); 
MyType t = myFunction(); 

kehrt als Referenz zurück. Dies wird höchstwahrscheinlich undefined Verhalten sein, da es illegal ist, lokale Objekte als Referenz zurückzugeben. Wenn myFunctions jedoch eine Elementfunktion ist, können Sie eine MyType, die ein Mitglied der Klasse ist, zurückgeben, und es wäre in Ordnung, solange die Instanz t überlebt.

Für das zweite Code-Snippet sollten Sie eine Warnung erhalten - "lokale Variable durch Referenz zurückgeben" oder etwas Ähnliches.

+0

@OliCharlesworth ja, tut mir leid, dass. Ich habe es sofort korrigiert. –

+0

"Es ist nicht erlaubt, lokale Objekte als Referenz zurückzugeben" ... wie soll ich also ein Objekt zurückgeben, das in der Funktion erstellt wurde? – Cheetah

+0

@Ben nach Wert - wie das erste Snippet. –

-1

denke ich, was Sie tun möchten, ist so etwas wie:

MyType *myFuntion() 
{ 
    MyType *t = new MyType; 
    // do something with t 
    return t; 
} 

// ... somewhere else ... 
MyType *t = myFunction(); 

heißt Sie ein neues Objekt in einer Funktion konstruieren und einen Zeiger darauf zurück. Vergiss nicht, anzurufen

delete t; 

irgendwo später!

0

Die meisten Antworten erhalten die Dinge richtig, bis auf ein kleines Detail.

const MyType& t = myFunction(); 

Es scheint, dass, wenn myFunction() eine temporäre Variable gibt diese nicht definiertes Verhalten sein würde, aber es ist nicht in der Realität. Dies ist nicht UB, und in der Tat verlängert die Konstante const die Lebensdauer des Temporären auf die Lebensdauer des Konstanten. Tatsächlich ist dies die eine Version mit dem größten Potenzial für die Compiler-Optimierung und gibt auch eine wichtige Lektion, dass man Rückgabewerte immer in eine const-Referenz aufnehmen sollte, wenn dies möglich ist.

+0

Ich bin mir nicht sicher, was Sie hier sagen wollen. Wenn 'myFunction()' einen Wert zurückgibt, ist es ein temporärer Wert. Immer. Und während die Lebensdauer des temporären (oder einer Kopie davon, in C++ 03) verlängert werden kann, gibt es absolut keinen Grund, 'MyType t = myFunction()' hier nicht zu verwenden. Wenn 'myFunction()' eine Referenz zurückgibt, ist dies ein undefiniertes Verhalten, unabhängig davon, was Sie mit dem Rückgabewert tun. –

+0

Yeah im Nachhinein sehe ich, dass ich der Narr bin, da ich die Funktion sig verpasst habe. Aber im Grunde, wenn 'MyType myFunction(); 'dann' const MyType & t = myFunction();' ist sowohl gültig als auch bevorzugt.'MyType t = myFunction();' mit der oben genannten Signatur ist eher eine oft unnötige temporäre tun (ohne auf die Besonderheiten von RVO & NRVO). – Ylisar

+1

Mehr oder weniger. Wenn 'myFunction()' als Wert zurückgibt, hat es keinen Sinn, es nicht zu verwenden, um einen Wert zu initialisieren; die lokale Variable zu einem Referenztyp zu machen, ist nur zusätzliches Rauschen. Wenn 'myFunction()' eine Referenz zurückgibt, die eine Polymorphie oder (wenn nicht konstante) Modifikation des Objekts (die anderswo existiert) erlaubt, könnte es leicht sinnvoll sein, eine lokale Referenz zu verwenden, um die Funktion nicht jedes Mal neu aufrufen zu müssen Zugriff auf das Objekt. –

Verwandte Themen