24

Können Sie mir den Unterschied zwischen Rückgabewert, Referenz auf Wert und const Referenz auf Wert erklären?C++ Rückgabewert, Referenz, Konstante Referenz

Wert:

Vector2D operator += (const Vector2D& vector) 
{ 
    this->x += vector.x; 
    this->y += vector.y; 
    return *this; 
} 

Nicht konstante Referenz:

Vector2D& operator += (const Vector2D& vector) 
{ 
    this->x += vector.x; 
    this->y += vector.y; 
    return *this; 
} 

Konst Referenz:

const Vector2D& operator += (const Vector2D& vector) 
{ 
    this->x += vector.x; 
    this->y += vector.y; 
    return *this; 
} 

Was i nützt das? Ich verstehe den Sinn hinter const Referenz übergeben an Funktion, wie Sie sicherstellen möchten, diesen Wert nicht zu ändern, auf den Verweis innerhalb einer Funktion verweist. Aber ich bin verwirrt durch die Bedeutung der Rückkehr const Referenz. Warum ist die Rückgabe der Referenz besser als die Rückgabe des Wertes und warum ist die Rückgabe der Konst-Referenz besser als die Rückgabe der Nicht-Konst-Referenz?

+3

mögliche Duplikate von Ihrem C++ Buch –

Antwort

16

Es gibt keinen Unterschied, wenn Sie etwas seltsam wie

(v1 += v2) = v3; 

Im ersten Fall schreiben, wird die Zuordnung zu einem vorübergehend sein, und die Gesamtwirkung v1 += v2 sein wird.

Im zweiten Fall lautet die Zuweisung zu v1, so dass der Gesamteffekt v1 = v3 ist.

Im dritten Fall ist die Zuweisung nicht erlaubt. Dies ist wahrscheinlich die beste Option, da solche Verrücktheit mit ziemlicher Sicherheit ein Fehler ist.

Warum die Rückgabe der Referenz ist besser als die Rückgabe des Wertes?

Es ist möglicherweise effizienter: Sie müssen keine Kopie des Objekts erstellen.

und warum ist die Rückgabe von const-Referenz besser als die Rückgabe von nicht-const Referenz?

Sie verhindern Seltsamkeit wie im obigen Beispiel, während noch weniger seltsame Verkettung ermöglicht wie

v1 = (v2 += v3); 

Aber, wie in den Kommentaren erwähnt, bedeutet dies, dass Ihre Art nicht die gleichen Formen unterstützt von (ab) als eingebaute Typen verwenden, die manche Leute für wünschenswert halten.

+1

Ich denke, es ist fraglich, ob "const" ist besser als nicht-const, können Sie nicht eine Methode aufrufen, die nicht-const auf das Ergebnis von '+ ='. Was ist mit '(v1 + = v2) .non_const_fun();'. Ich weiß, dass es eine Meinung ist, und ich gebe an, dass es vielleicht ein bisschen komisch aussieht, aber es macht mehr Sinn als '(v1 + = v2) = v3'. Ist es wirklich wichtig, es zu verbieten? – luk32

+2

@ luk32 Ich kann eine Menge Logik darin sehen, es zu verbieten, aber ... das eingebaute '+ =' gibt einen modifizierbaren Lvalue zurück und die Rückgabe eines nichtkonstanten Verweises ist dem eines benutzerdefinierten Typs am nächsten. Also das Prinzip der geringsten Überraschung --- benutzerdefinierte Operatoren sollten die eingebauten emulieren --- sagt nicht-const Referenz. –

+0

"const &" verhindert jedoch, dass 'v1 = std :: move (v2 + = v3)' sich tatsächlich bewegt. Nicht sicher, ob das interessant ist oder nicht. –

5

Es ist genau das gleiche wie übergeben Argument an die Funktion.

Sie möchten eine const Referenz zurückgeben, wenn Sie eine Eigenschaft eines Objekts zurückgeben, das nicht außerhalb davon geändert werden soll. Zum Beispiel: Wenn Ihr Objekt einen Namen hat, können Sie folgende Methode const std::string& get_name(){ return name; }; machen. Welches ist der optimalste Weg. Sie erlauben einen "schreibgeschützten" Zugriff auf eine interne Eigenschaft ohne Copy-on-Return.

Wenn Sie Operatoren überladen, wird erwartet, dass Sie ein Objekt zurückgeben, das veränderbar ist, andernfalls führt eine bestimmte Syntax, die normalerweise funktionieren soll, zu Fehlern. Es ist sehr wichtig, wenn Sie eine seltsame Verkettung versuchen.

Zum Beispiel Option 3 nicht mit so etwas wie (v1 += v2).non_const_method() arbeiten, während die folgenden würde:

v1+=v2; 
v1.non_const_method(); 
+0

Ok, es war nicht sauber für mich. So hat "const" direkt Auswirkungen auf das zurückgebende Objekt, so dass wir keine Kaskade von Funktionen darauf aufrufen können. Wenn wir das zurückgegebene Objekt unserem neuen Objekt zugewiesen haben, ist es nicht mehr const. Danke an euch alle! – Majak

1

Wie bereits ausgeführt, aber luk32 es nur, um sicherzustellen, dass keine Änderungen an den von dieser zurückgegebenen Objekte sind erlaubt Funktion. Dies kann Ihnen grundlegend dabei helfen, Ihre logischen Fehler zur Kompilierzeit zu finden. Angenommen, Sie möchten ein Objekt nicht ändern und Ihr Code ändert das Objekt, so dass es verfolgt werden kann. Es kann an eine gute Kodierungspraxis gedacht werden.

2

Der Unterschied zwischen Return-by-Wert und Return-by-reference Effekt während der Laufzeit nimmt:

Wenn Sie ein Objekt durch-Wert zurück, wird die Kopie-Konstruktor aufgerufen, und Eine temporäre Instanz wird auf dem Stapel erstellt.

Wenn Sie ein Objekt als Referenz zurückgeben, wird das oben Genannte nicht ausgeführt, was zu einer verbesserten Leistung führt.


Der Unterschied zwischen Return-by-reference und Return-by-Konstantreferenz keinen Laufzeiteffekt hat, und ist einfach da zum Schutz vor fehlerhaften Code zu schreiben.

Zum Beispiel mit Vector2D& operator += (const Vector2D& vector) können Sie tun:

(x+=y)++ oder (x+=y).func() wo funcVector2D eine nicht-konstante Funktion in der Klasse ist.

Aber mit const Vector2D& operator += (const Vector2D& vector) erzeugt der Compiler einen Fehler für einen solchen ähnlichen Versuch.

4

Wert:

von Wert Rückkehr bedeutet, dass Sie eine Kopie eines Objekts zurückkehren. Dies stellt Anforderungen an die Klasse (sie muss kopierbar oder beweglich sein). Dies bedeutet, dass das Zurückkehren nach Wert für einige Klassen teuer sein kann (in einem Fall, in dem RVO oder NRVO nicht funktioniert oder ausgeschaltet ist). Dies bedeutet auch, dass das neue Objekt unabhängig von seinem Design von anderen Objekten abhängig ist und einen eigenen Wert hat. Das sollten Sie wahrscheinlich von vielen binären Operatoren wie +, -, * und so weiter zurückgeben.

nicht konstante Referenz:

Sie wirklich ein Alias ​​für ein anderes Objekt zurück. Da der Alias ​​nicht const ist, können Sie Alias-Objekte ändern. Dies sollten Sie von einigen unären Operatoren wie Präfix ++ und - und * (Dereferenzierung) zurückgeben, da Sie normalerweise die Fähigkeit haben möchten, zurückgegebene Objekte zu modifizieren.

Dies wird von Operator >> zurückgegeben und Operator < < für Streams überlastet.Dies ermöglicht Verkettung von Operatoren:

cout << 5 << "is greater then" << 1 << endl; 
cin >> myInt >> myFloat; 

Sie auch zurückgeben kann auf * diese Option, wenn Sie möchten, wie diese Verkettung von regulären Methoden ermöglichen:

object.run().printLastRunStatistics(); 

Konst Referenz:

Wie oben, aber Sie können nicht Alias-Objekt ändern. Kann verwendet werden, anstatt nach Wert zurückzugeben, wenn das zurückzugebende Objekt teuer zu kopieren ist und wenn Sie nach der Rückkehr von einer Funktion sicherstellen können, dass das Objekt zurückgegeben wird.

Dies ist, was Operator = in der Regel mehr Zuweisungen in einer Art und Weise Standardtypen unterstützen, damit sie zurückgibt:

a = b = c; 

Konst Verweis in Operator verwendet = diese Art der Nutzung verhindert (nicht so weit von Standardtyp unterstützt wie ich mich erinnere):

++(a = b); 

die würde erlaubt sein, wenn normale referenz verwendet wurde.