Quelle est la différence entre l'opérateur d'affectation et le constructeur de copie?

105

Je ne comprends pas la différence entre le constructeur d'affectation et le constructeur de copie en C ++. C'est comme ça:

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

// The copy constructor
A a = b;

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

// Is it right?

Je veux savoir comment allouer la mémoire du constructeur d'affectation et du constructeur de copie?

alan.chen
la source
2
Avez-vous un bon livre C ++ ?
sbi
FAQ connexe
fredoverflow

Réponses:

160

Un constructeur de copie est utilisé pour initialiser un objet précédemment non initialisé à partir des données d'un autre objet.

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

Par exemple:

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

Un opérateur d'affectation est utilisé pour remplacer les données d'un objet précédemment initialisé par les données d'un autre objet.

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

Par exemple:

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

Vous pouvez remplacer la construction de la copie par la construction par défaut plus l'affectation, mais ce serait moins efficace.

(En remarque: mes implémentations ci-dessus sont exactement celles que le compilateur vous accorde gratuitement, il ne serait donc pas très judicieux de les implémenter manuellement. Si vous en avez une, il est probable que vous gériez manuellement certaines ressources. Dans ce cas, selon la règle de trois , vous aurez très probablement besoin de l'autre plus un destructeur.)

sbi
la source
4
Juste une note: de nos jours (à partir de C ++ 11), ils peuvent être explicitement définis par défaut avec =default;.
Deduplicator
2
@Deduplicator Il est également important de mentionner que, lorsque vous adhérez à des classifications qui nécessitent des constructeurs triviaux, vous devez = default les utiliser là où un cteur par défaut est nécessaire: simplement implémenter un corps vide par nous-mêmes compte toujours comme un ctor défini par l'utilisateur et donc (au niveau Standardese ) n'est pas trivial et disqualifie le type des classifications qui nécessitent un ctor trivial.
underscore_d
@sbi Puis-je dire que dans le cas où le constructeur de copie n'est pas utilisé et que l'opérateur d'affectation est utilisé, l'objet est d'abord créé en appelant le constructeur avec ou sans arguments, puis l'opérateur d'affectation est utilisé et de nouvelles valeurs sont attribuées en fonction de RHS. Dans le cas où le constructeur de copie est utilisé, le même constructeur sera appelé, mais les valeurs utilisées pour l'initialisation proviennent d'un autre objet.
Rajesh
@Rajesh: Je ne comprends pas ce que vous demandez, et mon sentiment est que vous êtes également confus. :)Essaierez-vous à nouveau d'expliquer de quoi vous parlez?
sbi
1
@ CătălinaSîrbu: Vous pourriez. Ce sont deux fonctions indépendantes.
sbi
41

La différence entre le constructeur de copie et l'opérateur d'affectation crée beaucoup de confusion pour les nouveaux programmeurs, mais ce n'est vraiment pas si difficile. En résumé:

  • Si un nouvel objet doit être créé avant que la copie puisse avoir lieu, le constructeur de copie est utilisé.
  • S'il n'est pas nécessaire de créer un nouvel objet avant que la copie puisse avoir lieu, l'opérateur d'affectation est utilisé.

Exemple d'opérateur d'affectation:

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

Exemple de constructeur de copie:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor
Arun
la source
Serait-il juste de dire qu'un opérateur d'assignation combine effectivement la destruction d'un ancien objet avec la création d'un nouveau, mais à condition que (1) si l'une des étapes de la destruction de l'ancien objet était annulée par l'une des étapes de la construction du nouveau, les deux étapes peuvent être omises; (2) les opérateurs d'affectation ne devraient pas faire de mauvaises choses si un objet est assigné à lui-même.
supercat du
pourquoi faire vector <A> v3et alors v3 = v2 (où v2est un élément précédemment déclaré et contenant vector<A>) appelle le Aconstructeur de copie de mon explicite à la place le operator=? Je m'attendais operator=à être appelé à la place du copy constructorcar mon v3objet était déjà déclaré au moment où j'ai effectué la mission
Cătălina Sîrbu
19

Le premier est l'initialisation de la copie, le second n'est que l'affectation. Il n'y a pas de constructeur d'affectation.

A aa=bb;

utilise le constructeur de copie généré par le compilateur.

A cc;
cc=aa;

utilise le constructeur par défaut pour construire cc, puis l'opérateur d'affectation * ** ( operator =) sur un objet déjà existant.

Je veux savoir comment allouer la mémoire du constructeur d'affectation et du constructeur de copie?

IDK ce que vous entendez par allouer de la mémoire dans ce cas, mais si vous voulez voir ce qui se passe, vous pouvez:

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;}
};

Je vous recommande également de jeter un œil à:

Pourquoi le constructeur de copie est-il appelé au lieu du constructeur de conversion?

Quelle est la règle de trois?

Luchian Grigore
la source
5

En quelques mots,

Le constructeur de copie est appelé lorsqu'un nouvel objet est créé à partir d'un objet existant, en tant que copie de l'objet existant. Et l'opérateur d'affectation est appelé lorsqu'un objet déjà initialisé reçoit une nouvelle valeur d'un autre objet existant.

Exemple-

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

Ce que @Luchian Grigore Said est implémenté comme ceci

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
}

PRODUCTION


constructeur par défaut


constructeur de copie


constructeur par défaut


opérateur d'assignation


Mak
la source
4

la différence entre un constructeur de copie et un constructeur d'affectation est:

  1. Dans le cas d'un constructeur de copie, il crée un nouvel objet. ( <classname> <o1>=<o2>)
  2. Dans le cas d'un constructeur d'affectation, il ne créera aucun objet, ce qui signifie qu'il s'applique aux objets déjà créés ( <o1>=<o2>).

Et les fonctionnalités de base dans les deux sont les mêmes, ils copieront les données de o2 vers o1 membre par membre.

Nitesh Kumar
la source
2

Je veux ajouter un autre point sur ce sujet. "La fonction d'opérateur de l'opérateur d'affectation doit être écrite uniquement en tant que fonction membre de la classe." Nous ne pouvons pas en faire une fonction amie contrairement à d'autres opérateurs binaires ou unaires.

MD BELAL RASHID
la source
1

Quelque chose à ajouter à propos du constructeur de copie:

  • Lors du passage d'un objet par valeur, il utilisera le constructeur de copie

  • Lorsqu'un objet est renvoyé d'une fonction par valeur, il utilisera le constructeur de copie

  • Lors de l'initialisation d'un objet en utilisant les valeurs d'un autre objet (comme l'exemple que vous donnez).

Frank Shen
la source