Qual é a diferença entre o operador de atribuição e o construtor de cópia?

105

Não entendo a diferença entre o construtor de atribuição e o construtor de cópia em C ++. É assim:

class A {
public:
    A() {
        cout << "A::A()" << endl;
    }
};

// The copy constructor
A a = b;

// The assignment constructor
A c;
c = a;

// Is it right?

Eu quero saber como alocar memória do construtor de atribuição e do construtor de cópia?

alan.chen
fonte
2
Você tem um bom livro C ++ ?
sbi
FAQ relacionado
fredoverflow

Respostas:

160

Um construtor de cópia é usado para inicializar um objeto não inicializado anteriormente a partir dos dados de algum outro objeto.

A(const A& rhs) : data_(rhs.data_) {}

Por exemplo:

A aa;
A a = aa;  //copy constructor

Um operador de atribuição é usado para substituir os dados de um objeto inicializado anteriormente pelos dados de algum outro objeto.

A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}

Por exemplo:

A aa;
A a;
a = aa;  // assignment operator

Você poderia substituir a construção de cópia por construção padrão mais atribuição, mas isso seria menos eficiente.

(Como uma observação lateral: Minhas implementações acima são exatamente as que o compilador concede a você gratuitamente, então não faria muito sentido implementá-las manualmente. Se você tiver uma dessas duas, é provável que esteja gerenciando algum recurso manualmente. Nesse caso, de acordo com a Regra de Três , você provavelmente também precisará do outro mais um destruidor.)

sbi
fonte
4
Apenas uma observação: hoje em dia (C ++ 11 em diante), eles podem ser explicitamente padronizados com =default;.
Deduplicator
2
@Deduplicator Também é importante mencionar que, ao aderir a classificações que requerem construtores triviais, você deve = default usá-las onde um ctor padrão é necessário: simplesmente implementar um corpo vazio por nós mesmos ainda conta como um ctor definido pelo usuário e, portanto (em um nível Standardese ) não é trivial e desqualifica o tipo de classificações que requerem um ctor trivial.
sublinhado_d
@sbi Posso dizer que, caso o construtor de cópia não seja usado e, em vez disso, o operador de atribuição seja usado, o objeto é criado primeiro chamando o construtor com argumentos ou sem argumentos e, em seguida, o operador de atribuição é usado e novos valores são atribuídos com base no RHS. Caso o construtor de cópia seja usado, o mesmo construtor será chamado, mas os valores usados ​​para a inicialização são de outro objeto.
Rajesh
@Rajesh: Estou confuso sobre o que você está perguntando, e acho que é porque você também está confuso. :)Você tentará explicar novamente sobre o que está falando?
sbi
1
@ CătălinaSîrbu: Você poderia. São duas funções independentes.
sbi
41

A diferença entre o construtor de cópia e o operador de atribuição causa muita confusão para novos programadores, mas realmente não é tão difícil. Resumindo:

  • Se um novo objeto tiver que ser criado antes que a cópia possa ocorrer, o construtor de cópia é usado.
  • Se um novo objeto não precisa ser criado antes que a cópia possa ocorrer, o operador de atribuição é usado.

Exemplo para operador de atribuição:

Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator

Exemplo de construtor de cópia:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor
Uma corrida
fonte
Seria justo dizer que um operador de atribuição combina efetivamente a destruição de um objeto antigo com a criação de um novo, mas com as ressalvas de que (1) se uma das etapas na destruição do objeto antigo seria desfeita por uma das etapas na construção do novo, ambas as etapas podem ser omitidas; (2) os operadores de atribuição não devem fazer coisas ruins se um objeto for atribuído a si mesmo.
supercat
por que fazer vector <A> v3e então v3 = v2 (onde v2está um elemento previamente declarado e contendo vector<A>) chama meu Aconstrutor de cópia explícito em vez de operator=? Eu esperava operator=ser chamado em vez de copy constructorporque meu v3objeto já havia sido declarado no momento em que fiz a atribuição
Cătălina Sîrbu,
19

O primeiro é a inicialização da cópia, o segundo é apenas atribuição. Não existe construtor de atribuição.

A aa=bb;

usa o construtor de cópia gerado pelo compilador.

A cc;
cc=aa;

usa o construtor padrão para construir cce, em seguida, o * operador de atribuição ** ( operator =) em um objeto já existente.

Eu quero saber como alocar memória do construtor de atribuição e do construtor de cópia?

IDK o que você quer dizer com alocar memória neste caso, mas se quiser ver o que acontece, você pode:

class A
{
public :
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

Eu também recomendo que você dê uma olhada em:

Por que o construtor de cópia é chamado em vez do construtor de conversão?

Qual é a regra de três?

Luchian Grigore
fonte
5

Em palavras simples,

O construtor de cópia é chamado quando um novo objeto é criado a partir de um objeto existente, como uma cópia do objeto existente. E o operador de atribuição é chamado quando um objeto já inicializado é atribuído a um novo valor de outro objeto existente.

Exemplo-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"
Satish
fonte
4

O que @Luchian Grigore Said é implementado assim

class A
{
public :
    int a;
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

void main()
{
    A sampleObj; //Calls default constructor
    sampleObj.a = 10;

    A copyConsObj  = sampleObj; //Initializing calls copy constructor

    A assignOpObj; //Calls default constrcutor
    assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}

RESULTADO


construtor padrão


construtor de cópia


construtor padrão


operador de atribuição


Mak
fonte
4

a diferença entre um construtor de cópia e um construtor de atribuição é:

  1. No caso de um construtor de cópia, ele cria um novo objeto. ( <classname> <o1>=<o2>)
  2. No caso de um construtor de atribuição não criará nenhum objeto, significa que se aplica a objetos já criados ( <o1>=<o2>).

E as funcionalidades básicas em ambos são iguais, eles irão copiar os dados de o2 para o1 membro a membro.

Nitesh Kumar
fonte
2

Eu quero adicionar mais um ponto sobre este tópico. "A função de operador do operador de atribuição deve ser escrita apenas como uma função de membro da classe." Não podemos torná-la uma função amiga ao contrário de outro operador binário ou unário.

MD BELAL RASHID
fonte
1

Algo a acrescentar sobre o construtor de cópia:

  • Ao passar um objeto por valor, ele usará o construtor de cópia

  • Quando um objeto é retornado de uma função por valor, ele usará o construtor de cópia

  • Ao inicializar um objeto usando os valores de outro objeto (conforme o exemplo que você deu).

Frank Shen
fonte