Semantik und Operatorüberladung verschieben

8

Dies steht im Zusammenhang mit dieser Antwort von Matthieu M. zur Verwendung der Bewegungssemantik mit dem Überladen des + -Operators ( im Allgemeinen, Operatoren, die nicht direkt wieder auf den linken Param umleiten).

Er schlug vor, drei verschiedene Überladungen zu implementieren:

%Vor%

Nummer 1 und 3 ergeben Sinn, aber ich verstehe nicht, welchen Zweck 2 hat. Der Kommentar schlägt eine kommutative Behandlung vor, aber es scheint, dass sich 1 und 2 gegenseitig ausschließen (d. H. Beide Ergebnisse in Mehrdeutigkeiten implementieren)

Zum Beispiel mit allen 3 implementiert:

%Vor%

Compiler-Ausgabe:

%Vor%

entfernt entweder 1 oder 2 und das Programm funktioniert wie erwartet. Da 1 der allgemeine Fall ist und 2 nur korrekt mit einem kommutativen Operator funktioniert, sehe ich nicht, warum 2 jemals verwendet werden würde. Gibt es etwas, das mir fehlt?

    
helloworld922 21.04.2013, 21:35
quelle

2 Antworten

11

Ich glaube nicht, dass du etwas verpasst hast - der Code in deiner Frage ist tatsächlich ein Problem. Der frühere Teil seiner Antwort ergab einen Sinn, aber etwas ging zwischen den "vier gewünschten Fällen" und dem tatsächlichen Beispiel verloren.

Das könnte besser sein:

%Vor%

Dies implementiert die Regel: Erstellen Sie eine Kopie der LHS (vorzugsweise über Move Construction), es sei denn, die RHS läuft sowieso ab, in diesem Fall ändern Sie sie an Ort und Stelle.

Bei nichtkommutativen Operatoren sollten Sie die zweite Überladung auslassen oder eine Implementierung bereitstellen, die nicht an die Verbundzuordnung delegiert.

Wenn in Ihrer Klasse schwergewichtige Ressourcen eingebettet sind (so dass sie nicht effizient verschoben werden können), sollten Sie den Wert "Pass-by-Value" vermeiden. Daniel macht einige gute Punkte in seiner Antwort. Aber geben Sie nicht T&& zurück, wie er es vorschlägt, da dies eine freie Referenz ist.

    
Ben Voigt 21.04.2013, 21:40
quelle
6
  

Wichtiges Update / Warnung zu dieser Antwort!

     

Tatsächlich ist ein überzeugendes Beispiel , das stillschweigend eine unpassende Referenz in vernünftigen Realitäten erstellt. Weltcode mit dem unten. Bitte verwenden Sie die Technik der anderen Antwort, um dieses Problem zu vermeiden, selbst wenn einige zusätzliche Provisorien erstellt werden. Ich lasse den Rest dieser Antwort unberührt für zukünftige Referenz.

Die richtigen Überladungen für einen kommutativen Fall sind:

%Vor%

Warum ist das und wie funktioniert es? Beachten Sie zunächst, dass Sie, wenn Sie eine R-Wert-Referenz als Parameter verwenden, diese ändern und zurückgeben können. Der Ausdruck, von dem er stammt, muss sicherstellen, dass der rvalue nicht vor dem Ende des vollständigen Ausdrucks zerstört wird, einschließlich operator+ . Das bedeutet auch, dass operator+ einfach die rvalue-Referenz zurückgeben kann, da der Aufrufer das Ergebnis von operator+ (das Teil von demselben Ausdruck ist) verwenden muss, bevor der Ausdruck vollständig ausgewertet wurde und die Provisorien (Ravlues) sind zerstört.

Die zweite wichtige Beobachtung ist, wie dies noch mehr Provisorien speichert und Operationen verschiebt. Betrachten Sie den folgenden Ausdruck:

%Vor%

mit dem oben genannten entspricht es:

%Vor%

vergleiche das mit dem, was mit dem anderen Ansatz passiert:

%Vor%

was bedeutet, dass Sie immer noch drei Provisorien haben und obwohl sie verschoben anstatt kopiert werden, ist der obige Ansatz wesentlich effizienter, wenn Sie Provisorien ganz vermeiden wollen.

Eine vollständige Bibliothek mit Unterstützung für noexcept finden Sie unter df.operators . Dort finden Sie auch Versionen für nichtkommutative Fälle und Operationen für gemischte Typen.

Hier ist ein komplettes Testprogramm, um es zu testen:

%Vor%     
Daniel Frey 21.04.2013 22:41
quelle