Constructeur de copie et l'opérateur = surcharge en C++: est une fonction commune possible?
Depuis un constructeur de copie
MyClass(const MyClass&);
et un opérateur = surcharge
MyClass& operator = (const MyClass&);
ont à peu près le même code, le même paramètre, et ne diffèrent que sur le retour, est-il possible d'avoir une fonction commune pour les deux à utiliser?
- "...ont à peu près le même code..."? Hmm... Vous devez être en train de faire quelque chose de mal. Essayez de réduire la nécessité d'utiliser des fonctions définies par l'utilisateur pour le présent et laisser le compilateur faire tout le sale boulot. Cela signifie souvent l'encapsulation des ressources dans leur propre objet membre. Vous pourriez nous montrer un peu de code. Nous avons peut-être certains de la bonne conception des suggestions.
- Double Possible de la Réduction de la duplication de code entre l'opérateur= et le constructeur de copie
Vous devez vous connecter pour publier un commentaire.
Oui. Il y a deux options communes. - Ce qui est généralement déconseillé - est d'appeler le
operator=
du constructeur de copie explicitement:Cependant, en fournissant un bon
operator=
est un défi quand il s'agit de traiter avec l'ancien état et des questions découlant de l'auto attribution. Aussi, tous les membres et les bases obtenir initialisé par défaut en premier, même si elles sont cédées à partir deother
. Cela peut même ne pas être valable pour tous les membres et les bases, et même si il est valide, il est sémantiquement redondante et peut être pratiquement cher.De plus en plus populaire, la solution est de mettre en œuvre
operator=
en utilisant le constructeur de copie et une méthode d'échange.ou encore:
Un
swap
fonction est généralement simple à écrire qu'il vient de swaps de la propriété de l'intérieur et ne pas avoir à nettoyer état existant ou d'allouer de nouvelles ressources.Avantages de la copie et de swap idiome, c'est qu'il est automatiquement auto-attribution de sécurité et de fournir de l'échange de l'opération n'est pas remise est également fortement exception coffre-fort.
Fortement exception coffre-fort, une "main" écrit opérateur d'affectation a généralement à attribuer une copie des nouvelles ressources avant de l'allocation du cessionnaire de la vieille ressources, de sorte que si une exception se produit l'allocation de nouvelles ressources, l'ancien état peut encore être retournés pour. Tout cela n'est gratuit à partir d'un copier-and-swap, mais est généralement plus complexe, et donc source d'erreurs, de le faire à partir de zéro.
La seule chose à faire attention est de s'assurer que la méthode d'échange est un véritable échange, et non pas la valeur par défaut
std::swap
qui utilise le constructeur de copie et l'opérateur d'affectation de lui-même.Généralement un memberwise
swap
est utilisé.std::swap
fonctionne et est "pas de jeter" garanti avec tous les types de base et les types pointeur. La plupart des pointeurs intelligents peuvent également être échangé avec un pas de jet de garantie.operator=
à partir de la copie ctor est en fait assez mauvais, parce qu'il initialise tout d'abord, toutes les valeurs par défaut juste de les remplacer avec les autres objets de valeurs par la suite.operator=
à partir d'un constructeur de copie n'est pas bonne, mais que vous n'avez à regarder raisonnable au sujet du monde réel code pour voir comment il est.assign
membre de la fonction utilisée par la copie ctor et opérateur d'affectation dans certains cas (pour les classes légères). Dans d'autres cas (à forte intensité de ressources/à l'aide de cas, poignée/corps) un copier/swap est le chemin à parcourir, bien sûr.new
ou de faire toute sorte de l'allocation des ressources, vous commencez à avoir à réfléchir à vos options un peu plus de soin.operator=
et il semble inefficace.T a(b);
a été défini waaay dos: d'abord appeler le constructeur par défaut et ensuite appeler l'opérateur d'affectation. Depuis cela s'est avéré être trop inefficaces, la notion de "constructeur de copie" a été introduit en C++ 🙂operator=
est écrit correctement, il ne devrait pas donner lieu à un accident.MyClass(other).swap(*this);
outhis->swap(MyClass(other));
?Le constructeur de copie exécute le premier temps de l'initialisation des objets utilisés pour être cru de la mémoire. L'opérateur d'affectation, otoh, que, remplace les valeurs existantes par de nouvelles. Plus souvent que jamais, cela implique de rejeter la vieille ressources (par exemple, la mémoire) et de l'allocation de nouveaux.
Si il y a une similitude entre les deux, c'est que la cession de l'opérateur effectue la destruction et la copie de la construction. Certains développeurs ont utilisé pour la mise en œuvre de la cession en place de destruction suivie par le placement de copie de la construction. Cependant, c'est un très mauvaise idée. (Si c'est l'opérateur d'affectation d'une classe de base qui a appelé lors de l'affectation d'une classe dérivée?)
Ce qui est généralement considéré comme la forme canonique de l'idiome de nos jours est à l'aide de
swap
que Charles a proposé:Il utilise la copie de la construction (à noter que
other
est copié) et la destruction (il est détruit à la fin de la fonction) -- et il les utilise dans le bon ordre, trop: la construction (peut échouer) avant la destruction (qui ne doit pas échouer).swap
être déclarévirtual
?Quelque chose qui me dérange à propos de:
Tout d'abord, la lecture de la parole "swap" quand mon esprit est la pensée de la "copie" irrite mon bon sens. Aussi, je m'interroge sur le but de cette fantaisie truc. Oui, toutes les exceptions dans la construction de la nouvelle (copie) des ressources devrait se faire avant le swap, ce qui semble être un moyen sûr de s'assurer que toutes les nouvelles données est rempli avant de le faire vivre.
C'est très bien. Donc, concernant les exceptions qui se produisent après l'échange? (quand la vieille ressources sont détruits lorsque l'objet temporaire est hors de portée) du point De vue de l'utilisateur de la mission, l'opération a échoué, sauf qu'il n'a pas. Il a un énorme effet de bord: la copie ne se produisent réellement. C'était seulement un nettoyage des ressources qui a échoué. L'état de l'objet de destination a été modifié, même si l'opération semble de l'extérieur de l'échec de la.
Donc, je propose plutôt de "swap" pour faire plus naturel "transfert":
Il y a encore de la construction de l'objet temporaire, mais la prochaine action immédiate est de libérer toutes les ressources actuelles de la destination, avant de se déplacer (et Invalide donc ils ne seront pas en double-libéré) les ressources de la source.
Au lieu de { construire, de se déplacer, détruire }, je propose { construire, détruire, déplacer }. Le mouvement, qui est le plus dangereux de l'action, qui est pris en dernier après que tout a été réglé.
Oui, la destruction échouer est un problème dans l'un des deux systèmes. Les données sont endommagées (copiées lorsque vous ne pensiez pas que c'était) ou de perte (libéré lorsque vous ne pensiez pas que c'était). Perdu, c'est mieux que corrompu. Aucune donnée n'est mieux que de mauvaises données.
De transfert au lieu de swap. C'est ma suggestion de toute façon.
First, reading the word "swap" when my mind is thinking "copy" irritates
-> en tant Que bibliothèque de l'écrivain, tu sais généralement de pratiques communes (copie+swap), et la difficulté estmy mind
. Votre esprit est en fait caché derrière l'interface publique. C'est ce code réutilisable est tout au sujet.