2017-12-20 9 views
1

den folgenden Ausschnitt Betrachten:Wird ein Wert in diesem Fall bewegt wird

class Bar {...}; 
class Foo { 
    public: 
    Foo(const Bar& bar): bar_(bar) {} 
    private: 
    Bar bar_; 
}; 

int main() { 
    Foo foo({...}); // Passing an rvalue Bar object here. 
} 

Frage: wird das Objekt, das ich in den Foo Konstruktor kopiert werden generiert haben, oder wird es verschoben werden? Genauer gesagt, welche der folgenden Aussagen trifft zu?

  • Es wird immer kopiert.
  • Es wird immer bewegt (ich bin mir ziemlich sicher, dass es nicht der Fall ist).
  • Dies ist ein nicht spezifiziertes Verhalten.

Antwort

4

Es wird immer kopiert.

Die rvalue Sie erstellen Bindungen an eine Const Lvalue-Referenz. Aber selbst wenn es an eine rvalue-Referenz gebunden war, konstruieren Sie bar_(bar) aus einem lvalue (bar). Die Wertkategorie des Objekts, das an die Referenz gebunden ist, ist strittig, wichtig ist der Werttyp der Referenz selbst. Und wie bereits erwähnt, ist der Ausdruck bar ein Lvalue.

Als allgemeine und etwas grobe Faustregel ist jeder Ausdruck, der ein Name von etwas ist, ein Lvalue.

Wenn Sie beiden Bewegungen und Kopien in einem Konstruktor unterstützen wollen, der Weg nach vorn zu gehen, ist dies:

Foo(Bar bar): bar_(std::move(bar)) {} 

Jetzt bar kann entweder durch eine Bewegung einer Kopie konstruiert werden, abhängig von der Quelle, und Ihr Mitglied wird aus einem Objekt konstruiert, aus dem Sie sicher aussteigen können. Dies zieht natürlich immer einen zusätzlichen Zug nach sich. Wenn Sie es vermeiden möchten, dann sind zwei c'tors erforderlich:

Foo(const Bar& bar): bar_(bar) {} 
Foo(Bar&& bar): bar_(std::move(bar)) {} 
+0

Das ist, was ich erwartet habe. Aber ist das nicht eine der Situationen, in denen es sicher ist, den Umzug anstelle der Kopie zu machen? Ich hoffte irgendwie, dass moderne Compiler diese Optimierung für mich tun könnten, was mir erlaubte, eine (besser lesbare) Referenzform zu behalten und nicht die Leistung zu opfern. Aber das würde natürlich dieses unspezifische Verhalten ausmachen. Du sagst also, dass das im Standard behoben ist und kopiere niemals durch Verschieben hier ersetzt werden kann, oder? –

+0

@SolenodonParadoxus - Es ist nicht sicherer. Der Umzug erfolgt lokal, im C'tor. Aber das Argument muss nicht an einen 'rvalue' gebunden sein (das Objekt befindet sich außerhalb der Funktion). Denk an eine separate Zusammenstellung. Du verbindest ein Objekt mit dir c'tor (das geht davon aus, dass es nur rvalues ​​speist). Und dann tu das: 'Bar b; Foo f (b); '. Es ist legal C++. Du kannst es nicht ungesetzlich machen. – StoryTeller

+0

@SolenodonParadoxus - Und ja, eine Kopie ist eine Kopie. Wenn wir einen Zug wollen, müssen wir einen Zug buchstabieren. – StoryTeller

Verwandte Themen