Warum wirft die lokale Variable den Konstruktor move?

19

Vor kurzem habe ich mit rvalues ​​"gespielt", um ihr Verhalten zu verstehen. Das meiste Ergebnis überraschte mich nicht, aber dann sah ich, dass, wenn ich eine lokale Variable werfe, der Move-Konstruktor aufgerufen wird.

Bis dahin dachte ich, dass der Zweck der Bewegungssemantikregeln darin besteht, zu garantieren, dass sich das Objekt nur dann bewegt (und ungültig wird), wenn der Compiler erkennt, dass es nicht mehr benutzt wird (wie in temporären Objekten) Benutzerversprechen, es nicht zu verwenden (wie in std :: move).

Im folgenden Code wurde jedoch keine dieser Bedingungen beibehalten, und meine Variable wird immer noch verschoben (zumindest bei g ++ 4.7.3).

Warum ist das so?

%Vor%     
asaelr 05.06.2013, 11:39
quelle

2 Antworten

5

Im vorliegenden Fall handelt es sich wahrscheinlich um einen Compiler-Fehler, weil auf die Variable, die geworfen wird (und von der sie verschoben wird), später Bezug genommen wird.

Im allgemeinen Fall ist das Verschieben von throw konzeptionell dasselbe wie das Verschieben von return . Es empfiehlt sich, move automatisch aufzurufen, wenn bekannt ist, dass die Variable nach dem angegebenen Punkt nicht referenziert werden konnte ( throw oder return ).

    
Juraj Blaho 05.06.2013, 11:50
quelle
7

C ++ Standard sagt (15.1.3):

Eine Ausnahme auslösen copy-initialisiert (8.5, 12.8) ein temporäres Objekt , das als Ausnahmeobjekt bezeichnet wird. Das temporäre ist ein lvalue und wird verwendet, um die Variable zu initialisieren, die in dem passenden Handler (15.3) genannt wird.

Dieser Absatz könnte auch hier relevant sein (12.8.31):

Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung die Kopier- / Verschiebungskonstruktion eines Klassenobjekts weglassen, selbst wenn der Konstruktor, der für die Kopier- / Verschiebungsoperation und / oder den Destruktor für das Objekt ausgewählt wurde, Nebenwirkungen aufweist >. In solchen Fällen behandelt die Implementierung die Quelle und das Ziel der ausgelassenen Kopier- / Verschiebungsoperation als einfach zwei verschiedene Arten, sich auf dasselbe Objekt zu beziehen, und die Zerstörung dieses Objekts tritt zu einem späteren Zeitpunkt auf, wenn die beiden Objekte ohne Optimierung zerstört worden wären. Diese Eliminierung von Kopier- / Verschiebevorgängen, die als Kopierauslöschung bezeichnet wird, ist unter den folgenden Umständen zulässig (die kombiniert werden können, um mehrere Kopien zu eliminieren):

(...)

- in einem throw-Ausdruck , wenn der Operand der Name eines nichtflüchtigen automatischen Objekts ist (anders als ein Parameter function oder catch-clause) , dessen Gültigkeitsbereich nicht über das Ende von hinausgeht der innerste umschließende try-Block (falls vorhanden) , kann die Kopier- / Verschiebungsoperation vom Operanden zum Ausnahmeobjekt (15.1) weggelassen werden, indem das automatische Objekt direkt in das Ausnahmeobjekt
konstruiert wird

Eingecheckt in Visual Studio 2012, Auswirkung:

%Vor%

Es sieht tatsächlich wie ein Fehler in GCC aus.

    
Spook 05.06.2013 11:49
quelle