2016-05-23 12 views
0

Ich habe eine Klasse mit ein paar Felder, assignment c-tor und move c-tor:C++, wie zweideutig bewegen Bauer zu vermeiden

class A{ 
    std::vector<int> numbers; 
    int k; 


public: 

    A(std::vector<int> &&numbers, const int k): 
     numbers(numbers), // fast 
     k(k) 
    { 
     // logic 
    } 

    A(const std::vector<int> &numbers, const int k): 
     A(std::move(std::vector<int>(numbers)), k) // copy-and-move vector 
    { 
     // empty 
    } 
}; 

Ich möchte logic halten in einem c-tor und es von anderen nennen. Auch ich möchte schnell move-semantics unterstützen. Und ich muss explizit copy-and-move Argumente in der assignment c-tor.

Gibt es eine Möglichkeit, solche verschachtelte Konstruktion zu vermeiden und alle Vorteile, die ich oben aufgeführt habe, zu behalten?

+2

Sie haben 'std :: move' vergessen, so dass Ihr Konstruktor mit dem' && 'tatsächlich eine Kopie erstellt. Sie müssen die Zuweisungsvariante nicht explizit kopieren und verschieben, da Sie nicht sicher sind, warum Sie das tun. –

+0

@MooingDuck Warum? 'vector' hat einen' move c-tor', der 'std :: vector &&' als Argument akzeptiert. Warum sollte ich bereits verschobene Werte verschieben? – LibertyPaul

+1

@LibertyPaul Es hat einen Namen, also ist es ein lvalue: Sie brauchen std :: move, um es in den Aufruf von 'std :: vector ()' – kfsone

Antwort

2

Sie könnten einen Konstruktor auf die andere übertragen:

struct A 
{ 
    A(const std::vector<int> & v) : A(std::vector<int>(v)) {} 

    A(std::vector<int> && v) 
    : v_(std::move(v)) 
    { 
     // logic 
    } 

    // ... 
}; 

Der bewegliche Konstruktor jetzt so schnell ist, wie es sein kann, und die Kopier Konstruktor Kosten einen Zug, als wenn Sie beide Konstrukteure buchstabieren. Wenn Sie bereit sind, einen zusätzlichen Schritt zu zahlen, obwohl, könnte man genauso gut haben nur einen einzigen Konstruktor:

struct A 
{ 
    A(std::vector<int> v) 
    : v_(std::move(v)) 
    { 
     // logic 
    } 
}; 

Die Alternative den gemeinsamen Code in eine Funktion zu setzen und rufen, dass von beiden Konstrukteure.

+0

zurück zu einem rvalue zu promoten Gibt 'std :: vector (v) 'produziert' std :: vector && '? Und wenn ja, warum sollte ich es wieder bewegen? Akzeptiert "Vektorkonstruktor" nicht 'std :: vector &&' was wir als Argument erhalten haben? – LibertyPaul

+1

@LibertyPaul: Alles mit einem Namen ist ein Lvalue. Nur weil der Parameter den gelieferten Wert erfordert, ist ein R-Wert nicht gleichbedeutend mit einem R-Wert. – GManNickG

+3

@kfsone: Nein: 'std :: move' ist eine Funktion und das Ergebnis des Funktionsaufrufs ist ein * Ausdruck *. Ausdrücke sind niemals Referenzen. Der richtige Weg, dies zu sagen, ist, dass 'std :: move' einen beliebigen Wert in einen rvalue umwandelt. –