2016-05-06 12 views
1

Das Buch C++ Primer sagtfehlgeschlagen C++ Primer über std :: move()

Es ist wichtig zu erkennen, dass der Anruf zu bewegen Versprechen zu verstehen, dass wir nicht die Absicht, RR1 wieder zu verwenden außer um es zuzuordnen oder zu zerstören.

Dies ist nach der Zeile:

int &&rr3 = std::move(rr1); 

Wie dieser Satz zu verstehen? Gibt es eine Änderung an rr1 nach dem Anruf std::move(rr1)?

Jemand dachte dieses Problem wurde in What is std::move(), and when should it be used? gelöst Aber ich bin nicht damit einverstanden. Das Buch geschrieben "Wir können ein verschobenes Objekt zerstören und ihm einen neuen Wert zuweisen, aber wir können den Wert nicht verwenden ein verschobenes Objekt. "Ich weiß nicht, was es bedeutet, dass wir den Wert eines verschobenen Objekts nicht verwenden können." Gibt es einen Code, der das erklären kann?

+0

Mögliche Duplikat [Was ist std :: move(), und wenn es verwendet werden soll?] (Http://stackoverflow.com/questions/3413470/what-is-stdmove-and-when- sollte es verwendet werden) – vaxquis

+0

'std :: move' selbst ändert das Objekt nicht. Es ändert seinen * Typ *, so dass die Zuweisung "rr1" ändern kann. (Obwohl in diesem Fall nicht). Da die Zuweisung den Wert von 'rr1' ändern kann, können Sie sich danach nicht darauf verlassen. – BoBTFish

+0

* Gibt es eine Änderung an rr1 nach dem Aufruf std :: move (rr1)? *. Nun ja. Manchmal. Das ist irgendwie der Punkt. Wenn Sie stuff * von * a * nach * b verschieben, ändern sich normalerweise sowohl a als auch b. Im C++ Fall kann sich ein * ändern * oder nicht. –

Antwort

0

Dieses spezielle Codebeispiel verfehlt den Punkt. std::move tut nichts mit dem Objekt, auf das es angewendet wird. Es ist nur ein anderes Format für eine Typumwandlung, und seine Auswirkung besteht darin, die Überladungsauflösung in Fällen zu steuern, in denen es darauf ankommt. Zum Beispiel:

void f(const my_type&); 
void f(my_type&&); 
my_type mm; 
f(mm);   // calls f(const my_type&) 
f(std::move(mm)); // calls f(my_type&&) 

Dies ist wichtig, da Funktionen, die rvalue Referenzen nehmen (in diesem Fall f(my_type&&)) werden in der Regel etwas tun, böse zu ihrem Argumente, um ihre Arbeit zu erleichtern. Der Kopierkonstruktor für std::vector erstellt beispielsweise eine Kopie des übergebenen Arguments. Der Move-Konstruktor stiehlt das interne Array des Arguments und lässt das Argument leer. Also, wenn Sie std::vector<int> vec(std::move(other_vector)); tun, sollten Sie nichts mit other_vector tun, außer ihm zuzuweisen oder zu zerstören, was die "Regel" sagt.

Das Problem mit dem Codebeispiel besteht darin, dass es nichts mit der rvalue-Referenz zu tun hat. Aus diesem Grund hat sich nichts im Objekt geändert und Sie können es weiterhin verwenden. Aber das ist eine dumme Verwendung von std::move, und ein sinnloses Beispiel.

0

move Semantik kann zufriedenstellend verstanden werden, wenn die Objekte dynamisch Speicher in ihnen zugewiesen haben.

class MemoryBlock 
{ 
    public: 
    MemoryBlock(size_t length) : _length(length), _data(new int[length]) 
    { 
    } 

    // copy constructor. 
    MemoryBlock(const MemoryBlock& other) : _length(other._length), _data(new int[other._length]) 
    { 
     std::copy(other._data, other._data + _length, _data); 
    } 

    // move copy constructor. 
    MemoryBlock(MemoryBlock&& other) : _data(nullptr), _length(0) 
    { 
     // Copy the data pointer and its length from the source object. 
     _data = other._data; 
     _length = other._length; 

     // Release the data pointer from the source object. 
     other._data = nullptr; 
     other._length = 0; 
    } 

    // destructor. 
    ~MemoryBlock() 
    { 
     if (_data != nullptr) 
     { 
       delete[] _data; 
     } 
     _length = 0; 
    } 

    private: 
    size_t _length; // The length of the resource. 
    int* _data; // The resource. 
}; 

// ok, 'a' has 20 byte memory inside it. 
MemoryBlock a(20); 

// we are literally transferring the memory from 'a' to 'b' by using move copy constructor. 
MemoryBlock b = std::move(a); 

// so you broke the promise: "that we do not intend to use object 'a' again" after it has been moved. 
// a::_data is now null and code will break. 
MemoryBlock c = a; 

//when object 'a' will go out of scope it can be destroyed properly 
//this will work because the promise holds: "that object can be destroyed" after it has been moved. 

//this will work, since you are copying the memory inside of 'd' to 'a' using normal copy constructor. 
//so you obeyed the promise: "that we can assign to object 'a'" after it has been moved. 
MemoryBlock d(30); 
MemoryBlock a = d;