2015-10-27 5 views
6

Von [12.8] [11] von N3337:Standard bewegt Konstruktor und Referenzelemente

Der implizit definierte Kopieren/Verschieben Konstruktor für eine nicht gewerkschaftlich Klasse X führen ein element Kopieren/Verschieben seiner Basen und Mitglieder. [Anmerkung: Klammer-oder-Gleich-Initialisierer von nicht statischen Datenelementen werden ignoriert. Siehe auch das Beispiel in 12.6.2. Anmerkung: Die Reihenfolge der Initialisierung entspricht der Reihenfolge der Initialisierung von Basen und Elementen in einem benutzerdefinierten Konstruktor (siehe 12.6.2). Sei x entweder der Parameter des Konstruktors oder für den Move-Konstruktor ein xvalue, der sich auf den Parameter bezieht. Jedes Basis- oder nicht statische Datenelement wird entsprechend seinem Typ kopiert/verschoben:

- Wenn das Element ein Array ist, wird jedes Element direkt mit dem entsprechenden Unterobjekt von x initialisiert;

- Wenn ein Element m den rvalue-Referenztyp T & & hat, wird es direkt initialisiert mit static_cast<T&&>(x.m);

- andernfalls wird die Basis oder das Element direkt mit der entsprechenden Basis oder dem Element von x initialisiert.

Dies ist wirklich mehr eine Klärung, aber ich kann keine Erwähnung von Lvalue Referenzmitglieder in dieser Klausel sehen. Da es sie nicht erwähnt, scheint es standardmäßig zu sagen, dass sie Teil der impliziten memberweisen Bewegung sind, doch das Folgende würde nicht funktionieren;

int x = 5; 
int& y = x; 
int& z(std::move(y)); //error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'std::remove_reference<int&>::type {aka int}' 

So ist es sicher davon ausgehen, dass der Standard-Bewegung Konstruktor unterscheidet, dass ein Mitglied eine Referenz ist, und würde einfach nur tun

int& z = y; 

ohne Aufruf std::move?

+0

Eine Lvalue-Referenz kann nicht an einen xvalue gebunden werden, also ist 'int & z (std :: move (y));' nicht zulässig. 'int &z = y;' ist legal und macht 'z' einen dritten Namen für das' int' Objekt, das momentan 'x' und' y' heißt. Ich bin mir nicht sicher, was deine Frage ist? –

+0

"Direct-Initialized" bedeutet, dass für ein Mitglied 'm', wird es initialisiert als ob durch' T m (other.m); –

+0

Ich denke, das ist mit http: // stackoverflow verwandt (und möglicherweise durch gelöst).com/questions/33344259/does-rvo-work-on-object-members – Sheljohn

Antwort

6

Es wird von der Spezifikation der Zugriffsausdrücke für Klassenmitglieder behandelt. Der wichtigste Teil ist

Let x entweder die Parameter des Konstruktors oder, für den Umzug Konstruktor sein, ein xValue auf den Parameter verweist.

Mit anderen Worten, ein Verzug geratenen Zug Konstruktor für

struct X { int x, &y; }; 

tut das Äquivalent von

X::X(X&& other) : x(std::move(other).x), y(std::move(other).y) {} 

Das hier Wichtigste ist, dass das Ergebnis einer Klasse Member-Access-Ausdruck x.m, wo m Benennt ein nicht statisches Datenelement, ist immer ein Lvalue, wenn m einen Referenztyp hat, aber ein xvalue, wenn x ein Rvalue undistist nicht referenziert. (Siehe [expr.ref]/4.) Dies stellt sicher, dass lvalue-Referenzelemente mit lvalues ​​initialisiert werden.

+1

'y (std :: move (andere) .y)' ist das gleiche wie 'y (other.y)', oder? –

+0

@ M.M Richtig, für referenzierte "y". –