O Construtor Move em C++
Este artigo apresentará como usar o construtor de movimentação em C++.
Use o Construtor de movimento para fornecer controle de cópia eficiente para classes em C++
O controle de cópia da classe define as funções básicas necessárias para especificar o que acontece quando o objeto da classe é copiado, movido, atribuído ou destruído. Essas funções têm nomenclatura C++ especial, como as funções construtor de cópia e construtor de movimento definem como um objeto é inicializado com outro objeto do mesmo tipo. As funções de atribuição de cópia e atribuição de movimentação definem como o objeto é atribuído ao mesmo tipo de objeto. Destructor
trata da rotina que é executada quando o objeto sai do escopo. É mais provável que algumas dessas funções sejam definidas pelo usuário, mas se não, o próprio compilador cria os protótipos padrão.
Quando o objeto de classe gerencia a memória dinâmica e os dados são muito grandes, as operações de cópia podem exigir muita computação. Eles podem usar recursos significativos que afetam o desempenho. Portanto, eles geralmente utilizam um construtor de movimento para reatribuir dados dinâmicos sem copiá-los para o novo local de memória. Isso é obtido atribuindo os ponteiros do objeto antigo aos membros correspondentes do objeto recém-inicializado ou atribuído. Observe que o exemplo a seguir não inclui o construtor de movimento e causa várias invocações do construtor de cópia, que delega para o construtor padrão.
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
class MyClass {
private:
int* data;
public:
explicit MyClass(int d) {
data = new int;
*data = d;
cout << "Constructor 1 is called" << endl;
};
MyClass(const MyClass& source) : MyClass(*source.data) {
cout << "Copy Constructor is called " << endl;
}
int getData() const { return *data; }
~MyClass() {
delete data;
cout << "Destructor is called" << endl;
}
};
void printVec(const vector<MyClass>& vec) {
for (const auto& i : vec) {
cout << i.getData() << " ";
}
cout << endl;
}
int main() {
vector<MyClass> vec;
vec.push_back(MyClass(10));
vec.push_back(MyClass(11));
printVec(vec);
cout << "------------------" << endl;
return EXIT_SUCCESS;
}
Resultado:
Constructor 1 is called
Constructor 1 is called
Copy Constructor is called
Destructor is called
Constructor 1 is called
Constructor 1 is called
Copy Constructor is called
Constructor 1 is called
Copy Constructor is called
Destructor is called
Destructor is called
10 11
------------------
Destructor is called
Destructor is called
Depois de definir um construtor de movimento, que geralmente deve ter a referência de valor r como o primeiro argumento (denotado com a notação &&
), a inicialização do vetor se torna mais eficiente à medida que os novos elementos do tipo MyClass
são adicionados. Como o construtor de movimento não aloca nova memória e assume o local mantido pelo objeto passado, é necessário atribuir nullptr
aos membros do objeto anterior. Caso contrário, o destruidor tentará liberar o mesmo local da memória duas vezes, lançando o erro em tempo de execução.
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
class MyClass {
private:
int* data;
public:
explicit MyClass(int d) {
data = new int;
*data = d;
cout << "Constructor 1 is called" << endl;
};
MyClass(const MyClass& source) : MyClass(*source.data) {
cout << "Copy Constructor is called " << endl;
}
MyClass(MyClass&& source) noexcept : data(source.data) {
source.data = nullptr;
cout << "Move Constructor is called" << endl;
}
int getData() const { return *data; }
~MyClass() {
delete data;
cout << "Destructor is called" << endl;
}
};
void printVec(const vector<MyClass>& vec) {
for (const auto& i : vec) {
cout << i.getData() << " ";
}
cout << endl;
}
int main() {
vector<MyClass> vec;
vec.push_back(MyClass(10));
vec.push_back(MyClass(11));
printVec(vec);
cout << "------------------" << endl;
return EXIT_SUCCESS;
}
Resultado:
Constructor 1 is called
Move Constructor is called
Destructor is called
Constructor 1 is called
Move Constructor is called
Move Constructor is called
Destructor is called
Destructor is called
10 11
------------------
Destructor is called
Destructor is called
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook