1
votes

Pourquoi les constructeurs de copie sont-ils nécessaires et dans quels cas ils sont très utiles?

Pourquoi exactement avons-nous besoin de constructeurs de copie?

J'étudie le C ++ et je ne suis pas en mesure de comprendre le besoin de constructeurs de copie, car sans utiliser également un constructeur de copie, j'obtenais une sortie correcte. J'ai parcouru quelques exemples, mais il m'a semblé que c'était juste une bonne pratique d'avoir des constructeurs de copie, comme pour initialiser des variables. Quelqu'un pourrait-il s'il vous plaît m'aider à comprendre le concept de constructeurs de copie. Toute aide sera très appréciée. Merci.


10 commentaires

Parce qu'une simple copie de valeur (comme C le fait) n'est pas suffisante pour les choses qui ne sont pas des valeurs, par ex. pointeurs ou autres poignées. Écrivez votre vecteur comme un exercice.


Est-ce que cela répond à votre question? Qu'est-ce que la règle de trois?


Disons que vous avez un objet complexe, qui a besoin d'un code non trivial à copier. Quelle autre manière de copier un tel objet proposeriez-vous? Le compilateur ne pourra pas générer automatiquement de code pour cela.


vous n'avez pas nécessairement besoin d'un constructeur de copie. Uniquement lorsque vous souhaitez copier des objets de construction;). Il y a des classes qui n'en ont pas


Vous pouvez utiliser Foo (Foo const &) = delete; pour vous passer du constructeur de copie de Foo.


@Sid Voulez-vous dire que «je peux copier mon objet sans définir de constructeur de copie»? Disons que pour struct foo {int x; };


Je pense que vous manquez le fait que si vous ne fournissez pas de constructeur de copie, le compilateur en générera un pour vous . Cela s'applique à chaque classe / struct en C ++. Le constructeur de copie généré par le compilateur est assez bon pour la plupart des classes, mais si vous gérez certaines ressources dans une classe (comme allouer quelque chose avec new ), vous devez fournir votre propre constructeur de copie.


@Yksisarvinen C'est la réponse à mon avis.


Pourquoi ne demandez-vous pas au créateur lui-même? - "18.3 Copie" - informit.com/articles/article.aspx? p = 2216986 & seqNum = 3 "Copier les constructeurs" ... Alors, que faisons-nous? Nous allons faire l'évidence: fournir une opération de copie qui copie les éléments et nous assurer que cette opération de copie est appelée lorsque nous initialisons un vecteur avec un autre. L'initialisation des objets d'une classe est effectuée par un constructeur. Nous avons donc besoin d'un constructeur qui copie. Sans surprise, un tel constructeur est appelé un constructeur de copie. Il est défini pour prendre comme argument une référence à l'objet à partir duquel copier. "


@lars Peut-être, mais pour moi, la question n'est pas claire. Nous ne savons pas pourquoi OP pense que les constructeurs de copie sont inutiles, et mon commentaire était basé sur une supposition qu'ils ne savent pas que chaque classe a un constructeur de copie.


4 Réponses :


3
votes

si vous passez vos objets aux méthodes via passage par copie, c ++ doit utiliser un constructeur de copie pour générer l'instance de cette classe pour le contexte de la méthode. par exemple, si vous stockez vos instances dans un vecteur, lorsque vous repoussez un objet, il appelle indirectement le constructeur de copie. Au fait, pour les classes, c ++ crée généralement un constructeur de copie par défaut s'il n'y en a pas explicitement implémenté, ce cas crée parfois des effets indésirables (copie superficielle).


0 commentaires

4
votes

Regardons l'exemple suivant

#include <iostream>
struct A {
    explicit A(int value) : data_(new int[1]) { data_[0] = value; }
    ~A() { delete [] data_; }

    int getValue() const { return data_[0]; }

  private:
    int *data_ = nullptr;
};

int main() {
    A a1(1);
    A a2(2);
    a2 = a1;
    std::cout << a2.getValue() << std::endl;
}

Si vous l'exécutez, le programme plantera.

Ce qui se passe ici, c'est que vous copiez le int * data_ de a1 à a2 puis la mémoire allouée par a2 est perdue.

Maintenant a1 et a2 ont les mêmes pointeurs. Et ils appelleront tous les deux des destructeurs pour libérer la mémoire. La mémoire sera libérée deux fois, ce qui provoquera un plantage.

Fournir un constructeur de copie correct résoudra ce problème.


2 commentaires

Impossible de se reproduire. Quand je compile, lie et exécute ce code, j'obtiens la sortie de 2 et aucun plantage du programme. Le comportement est en fait indéfini - il est trompeur de dire que cela plantera, car un crash n'est qu'un symptôme possible d'un comportement non défini.


Vous avez la bonne idée, mais a2 = a1; utilise l'opérateur d'affectation, pas le constructeur de copie. A a2 = a1; utiliserait le constructeur de copie.



1
votes

La règle de trois (également connue sous le nom de loi des trois grands ou des trois grands) est une règle empirique en C ++ (antérieure à C ++ 11) qui prétend que si une classe définit l'un des éléments suivants, alors elle devrait probablement définir explicitement les trois: destructeur. copier le constructeur. copier l’opérateur d’affectation.

Point principal: Le constructeur de copie est nécessaire lorsque vous avez une allocation de mémoire dynamique (tas) dans un constructeur d'objet, vous devez également faire une copie de la mémoire allouée aux nouveaux objets assignés. De cette façon, vous pourriez être en mesure de (Obj1 = Obj2 / Obj1 (Obj2)) et garantir que la mémoire dynamique sera également copiée.


1 commentaires

également après C ++ 11, la règle de trois est toujours pertinente, car tout ne peut / ne doit pas être mobile



5
votes

car sans utiliser également un constructeur de copie, nous pouvons obtenir le sortie

Ce n'est pas vraiment vrai. Vous n'avez pas écrit de constructeur de copie, mais vous obtenez la sortie souhaitée via un constructeur de copie, que votre compilateur écrit pour vous:

Si aucun constructeur de copie défini par l'utilisateur n'est fourni pour un type de classe (struct, class ou union), le compilateur déclarera toujours une copie constructeur en tant que membre public en ligne non explicite de sa classe

Voir https://en.cppreference.com/w/cpp/language/copy_constructor pour plus de détails sur les constructeurs de copie déclarés implicitement.


En bref, le constructeur de copie est la fonction qui est appelée lorsque vous copiez une instance de votre classe. Le compilateur l'écrit pour vous mais vous pouvez l'écrire vous-même si vous voulez qu'il fasse quelque chose de non trivial ( par exemple ne pas copier un pointeur mais copier l'objet vers lequel il pointe)


0 commentaires