Wie sollte ich Funktionsparameter schreiben, um eine Verschiebung und nicht eine Kopie zu erzwingen?

8

Ich möchte einen großen Container aus einem Rückgabewert mithilfe des Konstruktors dieser Klasse in eine andere Klasse verschieben. Wie formuliere ich den Parameter, um sicherzustellen, dass er nicht kopiert wird?

%Vor%

Wird obige Formulierung das entsprechende Verhalten auslösen, oder muss ich die Parameter des Konstruktors als rvalue-references angeben, so wie es die Container für ihre eigene move-semantics tun?

%Vor%

oder

%Vor%

...?

    
Adrian 08.01.2014, 19:31
quelle

4 Antworten

11

Wenn Sie das Kopieren von und unterstützen möchten, ist der einfachste Weg um nach Wert zu übergeben :

%Vor%

Nun können Sie Bar aus einem lvalue und einem rvalue konstruieren:

%Vor%

Wenn Sie nur rValues ​​unterstützen möchten, verwenden Sie eine explizite rvalue-Referenz:

%Vor%

Das std::move ist immer notwendig, da (m) immer ein lvalue ist.

    
Kerrek SB 08.01.2014, 19:40
quelle
4

Erzwinge die Übergabe von rvalue in den Konstruktor und stelle sicher, dass die Map wie folgt verschoben wird:

%Vor%

Beginnend mit dem ersten Beispiel bis zur obigen Lösung:

Beginnen wir mit dem ersten Beispiel von Bar(umap m) : bm(m) {} . Dies führt mindestens 1 Kopie, möglicherweise 2.

bm(m) wird immer kopiert. m ist hier lvalue , obwohl es an einen rvalue gebunden ist. Um es in Bewegung zu versetzen, müssen Sie es in std::move umbrechen, um es in einen rvalue umzuwandeln. Wir erhalten bm(std::move(m)) .

Bar(umap m) könnte kopieren. Der Wert wird verschoben, wenn es ein rvalue ist, wird aber kopiert, wenn es ein lvalue ist. Da wir alle Kopien verhindern wollen, müssen wir nur rvalue binden lassen. Wir erhalten Bar(umap && m) .

    
mpark 08.01.2014 19:35
quelle
1

Zusätzlich zu den obigen Antworten:

Was ich in Ihrem Beispiel sehe, ist ein klassischer Fall für die Optimierung "Kopieren Elision".

Was sind Kopieroptimierung und Rückgabewertoptimierung?

Ein tatsächlicher Compiler benötigt keine Unterstützung von Ihnen, um die Dinge zu optimieren, und es gibt keinen Grund, sich mit rvalue-Referenzen in diesem speziellen Fall der Rückgabewertoptimierung zu beschäftigen.

    
Klaus 08.01.2014 20:40
quelle
0

In C ++ 11 verwenden Sie std::move . Wenn Sie C ++ 03-Kompatibilität benötigen, können Sie default-construct bm via :bm() und dann using std::swap; swap(bm, m); verwenden.

    
Mehrdad 08.01.2014 19:53
quelle