Requisitos previos: referencias de valor l y valor r en C++ , Copiar constructor en C++ .
¿Qué es un constructor de movimiento?
Los constructores de copia en C++ funcionan con las referencias de valor l y la semántica de copia (la semántica de copia significa copiar los datos reales del objeto a otro objeto en lugar de hacer que otro objeto señale el objeto ya existente en el montón). Mientras que los constructores de movimiento trabajan en las referencias de valor r y semántica de movimiento (la semántica de movimiento implica apuntar al objeto ya existente en la memoria).
Al declarar el nuevo objeto y asignarle el valor r, primero se crea un objeto temporal y luego ese objeto temporal se usa para asignar los valores al objeto. Debido a esto, el constructor de copias se llama varias veces y aumenta la sobrecarga y disminuye la potencia computacional del código. Para evitar esta sobrecarga y hacer que el código sea más eficiente, usamos constructores de movimiento.
¿Por qué se utilizan los constructores de movimiento?
El constructor de movimiento mueve los recursos en el montón, es decir, a diferencia de los constructores de copia que copian los datos del objeto existente y lo asignan al nuevo objeto, el constructor de movimiento simplemente hace que el puntero del objeto declarado apunte a los datos del objeto temporal y lo anula. el puntero de los objetos temporales. Por lo tanto, el constructor de movimiento evita la copia innecesaria de datos en la memoria.
El constructor de trabajo de movimiento se parece un poco al constructor de copia de miembro predeterminado, pero en este caso, anula el puntero del objeto temporal, lo que impide que más de un objeto apunte a la misma ubicación de memoria.
A continuación se muestra el programa sin declarar el constructor de movimiento:
C++
// C++ program without declaring the // move constructor #include <iostream> #include <vector> using namespace std; // Move Class class Move { private: // Declaring the raw pointer as // the data member of the class int* data; public: // Constructor Move(int d) { // Declare object in the heap data = new int; *data = d; cout << "Constructor is called for " << d << endl; }; // Copy Constructor to delegated // Copy constructor Move(const Move& source) : Move{ *source.data } { // Copying constructor copying // the data by making deep copy cout << "Copy Constructor is called - " << "Deep copy for " << *source.data << endl; } // Destructor ~Move() { if (data != nullptr) // If the pointer is not // pointing to nullptr cout << "Destructor is called for " << *data << endl; else // If the pointer is // pointing to nullptr cout << "Destructor is called" << " for nullptr" << endl; // Free the memory assigned to // data member of the object delete data; } }; // Driver Code int main() { // Create vector of Move Class vector<Move> vec; // Inserting object of Move class vec.push_back(Move{ 10 }); vec.push_back(Move{ 20 }); return 0; }
Constructor is called for 10 Constructor is called for 10 Copy Constructor is called - Deep copy for 10 Destructor is called for 10 Constructor is called for 20 Constructor is called for 20 Copy Constructor is called - Deep copy for 20 Constructor is called for 10 Copy Constructor is called - Deep copy for 10 Destructor is called for 10 Destructor is called for 20 Destructor is called for 10 Destructor is called for 20
Explicación:
el programa anterior muestra el constructor de copia que llama innecesariamente y el uso ineficiente de la memoria al copiar los mismos datos varias veces como nuevo objeto en cada llamada al constructor de copia.
Sintaxis del constructor de movimiento:
Object_name(Object_name&& obj) : data{ obj.data } { // Nulling out the pointer to the temporary data obj.data = nullptr; }
Este uso innecesario de la memoria se puede evitar utilizando el constructor de movimientos. A continuación se muestra el programa que declara el constructor de movimiento:
C++
// C++ program with declaring the // move constructor #include <iostream> #include <vector> using namespace std; // Move Class class Move { private: // Declare the raw pointer as // the data member of class int* data; public: // Constructor Move(int d) { // Declare object in the heap data = new int; *data = d; cout << "Constructor is called for " << d << endl; }; // Copy Constructor Move(const Move& source) : Move{ *source.data } { // Copying the data by making // deep copy cout << "Copy Constructor is called -" << "Deep copy for " << *source.data << endl; } // Move Constructor Move(Move&& source) : data{ source.data } { cout << "Move Constructor for " << *source.data << endl; source.data = nullptr; } // Destructor ~Move() { if (data != nullptr) // If pointer is not pointing // to nullptr cout << "Destructor is called for " << *data << endl; else // If pointer is pointing // to nullptr cout << "Destructor is called" << " for nullptr " << endl; // Free up the memory assigned to // The data member of the object delete data; } }; // Driver Code int main() { // Vector of Move Class vector<Move> vec; // Inserting Object of Move Class vec.push_back(Move{ 10 }); vec.push_back(Move{ 20 }); return 0; }
Producción:
Constructor is called for 10 Move Constructor for 10 Destructor is called for nullptr Constructor is called for 20 Move Constructor for 20 Constructor is called for 10 Copy Constructor is called -Deep copy for 10 Destructor is called for 10 Destructor is called for nullptr Destructor is called for 10 Destructor is called for 20
Explicación:
La llamada innecesaria al constructor de copia se evita haciendo la llamada al constructor de movimiento. Por lo tanto, hace que el código sea más eficiente con la memoria y disminuye la sobrecarga de llamar al constructor de movimiento.
Publicación traducida automáticamente
Artículo escrito por justanotaku y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA