2016-12-23 2 views
1

Ich habe eine Frage über die Verwendung von std::move in C++.Mit std :: move mit Vektoren

Lassen Sie uns sagen, dass ich die folgende Klasse haben, die in seinem Konstruktor einen std::vector als Parameter übernimmt:

class A 
{ 
public: 
    A(std::vector<char> v): v(v) {} 
private: 
    std::vector<char> v; 
}; 

Aber wenn ich irgendwo schreiben folgendes:

std::vector<char> v; 
A a(v); 

der Kopierkonstruktor von std::vector Wird zweimal angerufen, oder? Also sollte ich Konstruktor für A wie folgt schreiben?

class A 
{ 
public: 
    A(std::vector<char> v): v(std::move(v)) {} 
private: 
    std::vector<char> v; 
}; 

Und was, wenn ich das folgende nennen möchte?

std::vector<char> v; 
A a(std::move(v)); 

Ist das in Ordnung mit der zweiten Version des Konstrukteurs, oder sollte ich einen anderen Konstruktor für A erstellen, die std::vector<char>&& nimmt?

Antwort

1

Ihr zweites Schema ist in Ordnung.

Der Vektor wird nur zweimal mit der zweiten Version verschoben (wodurch der Wert by-value in Ihr Member verschoben wird). Wenn es Ihnen nichts ausmacht, die zusätzlichen Kosten zu übernehmen, können Sie einfach den Parameter "by-value" in Ihr Mitglied verschieben.

Wenn Sie etwas dagegen haben, dann machen Sie zwei Konstruktoren für verschiedene Wertkategorien des Parameters.

0

Sie sollten einen Move-Konstruktor schreiben!

Wenn Sie das nicht geschrieben haben, erhalten Sie hier eine weitere Kopie.

Sie müssen bedenken, dass Ihr Vektor "weg" bewegt wird. Also, wenn Sie so etwas wie schreiben:

std::vector<char> v; 
A a(std::move(v)); 

so Ihr Vektor v sollte nach dem Aufruf des Konstruktor von A. Alle Elemente sind weggezogen und Iteratoren zum Inhalt ungültig sind nicht verwendet. Der Vektor kann zum Speichern neuer Daten verwendet werden.

Also, wenn Sie schreiben

std::vector<char> v; 
A a(v); 

und dies in einer Bewegung zur Folge haben wird, wie in Ihrem Beispiel, niemand den Umzug erwarten.

+0

Eigentlich kann ich lesen, dass Vektor nach dem Umzug verwendet werden kann: https://StackOverflow.com/Questions/9168823/reusing-a-Moved-Container – Igor

+0

Es gibt keine "weg" passiert. Der Vektor ist nach dem Verschieben leer. Sie können damit neue Werte speichern. Nur vorhandene Iteratoren sollten nicht verwendet werden. – StoryTeller

+0

Danke, ja, das klär ich in meiner Antwort – Klaus

1

Machen Sie zwei Konstruktoren: Der erste Konstruktor von const & sein sollte, die zweite als rvalue & & so kann es bewegen Semantik verwenden:

class A 
{ 
public: 
    A(const std::vector<char>& v_) : v(v_) { std::cout << "const& ctor\n"; } 
    A(std::vector<char>&& v_) : v(std::move(v_)) { std::cout << "rvalue&& ctor\n"; } 
private: 
    std::vector<char> v; 
}; 

Test:

int main() 
{ 
    std::vector<char> v1{ 'a', 'b', 'c', 'd' }; 
    A a1(v1); 
    A a2(std::vector<char>{ 1, 2, 3, 4 }); 
    return 0; 
} 

Ausgang:

const & Ctor

rvalue & & Ctor

1

Viele Male mit Vektoren würden Sie von ihm durch die Annahme vector von Wert und bewegt in Ordnung sein.So

A(std::vector<char> v): v(std::move(v)) {} 

Dies setzt allerdings voraus, dass Sie es nur fordern ‚natürliche‘ lvalues ​​oder Provisorien. Was bedeutet, wäre es für Fälle wie

A a(std::vector<char>{....}); // <--- 1 
std::vector<char> my_vec; 
A b(my_vec); // <--- 2 

performant sein, wenn Sie es mit einem L-Wert zu nennen erwarten, die Sie möchten aus, wie in Ihrem Beispiel zu bewegen, als Sie zwei Konstrukteure müssen - mit const lvalue Referenz- und rvalue Referenzen:

A(const std::vector<char>& v) : v(v) { } 
A(std::vector<char>&& v) : v(std::move(v)) { } 
Verwandte Themen