Pourquoi faut-il le copier l'opérateur d'assignation de renvoyer une référence/const référence?
En C++, le concept de renvoi de référence à partir de la copie opérateur d'affectation est pas clair pour moi. Pourquoi ne peut pas le copier opérateur d'affectation de renvoyer une copie de l'objet nouveau? En outre, si j'ai de la classe A
, et les suivantes:
A a1(param);
A a2 = a1;
A a3;
a3 = a2; //<--- this is the problematic line
La operator=
est définie comme suit:
A A::operator=(const A& a)
{
if (this == &a)
{
return *this;
}
param = a.param;
return *this;
}
- Il n'y a pas une telle exigence. Mais si vous voulez vous tenir au principe du moins surprize, vous serez de retour
A&
commea=b
est une lvalue expression faisant référence àa
en casa
etb
sont entiers. - Merci de me laisser savoir! Va le faire
- Pourquoi ne peux-nous de retour
A*
de l'opérateur d'assignation de copie je suppose que le chaînage de l'affectation fonctionne encore correctement. Quelqu'un peut-il aider à comprendre les dangers de retourA*
si il y a de tout. - Remarque: Depuis C++11, il est aussi le déplacer-opérateur d'affectation, tous de la même logique que dans ce Q & A s'applique également à la déplacer-opérateur d'affectation. En fait, ils pourraient être tous les deux la même fonction si a déclaré que
A & operator=(A a);
, par exemple, prendre l'argument par valeur. - La vraie question est de savoir pourquoi vous souhaitez retourner un pointeur. Pensez à la façon moche et ambigu du code de la surcharge d'opérateur et le retour serait le cas si nous n'avions que des pointeurs - dans les affaires les plus importantes, mortellement ambigu (aussi: mortellement laid). Et puis il suffit de lire le langage du créateur mots à propos de tout cela: stackoverflow.com/questions/8007832/...
Vous devez vous connecter pour publier un commentaire.
Strictement parlant, le résultat d'une copie opérateur d'affectation n'a pas besoin de retourner une référence, mais pour imiter le comportement par défaut le compilateur C++ utilise, il doit retourner un non-const référence à l'objet qui lui est assigné (un générées implicitement copie opérateur d'affectation sera de retour d'une non-const de référence - C++03: 12.8/10). J'ai vu un peu juste de code qui renvoie
void
à partir de la copie d'affectation des surcharges, et je ne me souviens pas quand cela a causé un grave problème. De retourvoid
empêchera les utilisateurs de "cession de chaînage' (a = b = c;
), et éviter d'utiliser le résultat d'une affectation dans une expression de test, par exemple. Alors que ce type de code est pas rare, aussi, je ne pense pas que c'est particulièrement commun - en particulier pour les non-types primitifs (à moins que l'interface d'une classe a l'intention de ces types de tests, comme pour iostreams).Je ne suis pas à vous recommander ce faire, il suffit de souligner que c'est autorisé et qu'il ne semble pas causer beaucoup de problèmes.
Ces autres DONC les questions sont liées (probablement pas tout à fait dupes) qui ont des informations et des opinions qui pourraient être d'intérêt pour vous.
Un peu de précisions quant à pourquoi il est préférable de retour par référence pour
operator=
contre le retour par valeur --- alors que la chaînea = b = c
fonctionnera bien si une valeur est retournée.Si vous retournez une référence minimale du travail est fait. Les valeurs d'un objet sont copiés vers un autre objet.
Toutefois, si vous revenez en valeur pour
operator=
, vous allez appeler un constructeur ET un destructeur à CHAQUE fois que l'opérateur d'affectation est appelé!!Donc, compte tenu de:
Puis,
Mais,
En somme, il n'y a rien de gagné par le renvoi de la valeur, mais beaucoup à perdre.
(Note: Ce n'est pas à l'adresse de l'avantage d'avoir de l'opérateur d'affectation de retour une lvalue. Lire les autres posts pour pourquoi ce serait peut-être préférable)
Quand vous surchargez
operator=
, vous peut l'écrire sur retour quel que soit le type que vous voulez. Si vous voulez assez mal, vous pouvez surchargeX::operator=
retour (par exemple) une instance de certaines complètement différente de la classeY
ouZ
. C'est généralement très déconseillé même si.En particulier, vous voulez généralement à l'appui de chaînage de
operator=
comme C ne. Par exemple:Cela étant le cas, habituellement, vous voulez retourner une lvalue ou rvalue du type qui est affecté. Qui ne laisse que la question de savoir si pour renvoyer une référence à X, const référence à X, ou X (en valeur).
Retour const référence à X est généralement une mauvaise idée. En particulier, const référence est autorisé à se lier à un objet temporaire. La durée de vie de la temporaire est prolongée de la durée de vie de la référence à laquelle il est lié, mais pas de manière récursive pour la durée de vie de ce que pourrait être attribué. De ce fait, il est facile de retourner un bancales référence--la const de référence se lie à un objet temporaire. Que l'objet de la durée de vie est prolongée de la durée de vie de la référence (qui se termine à la fin de la fonction). Par le temps, la fonction retourne une valeur, la durée de vie de la référence et temporaires ont pris fin, de sorte que ce qui est affecté est un bancales de référence.
Bien sûr, de retour d'un non-const de référence ne fournit pas une protection complète contre, mais au moins vous fait travailler un peu plus difficile à elle. Vous pouvez toujours (par exemple) définir certains locaux, et de renvoyer une référence (mais la plupart des compilateurs peut et va avertir à propos de cette trop).
De retourner une valeur au lieu d'une référence a la fois théorique et pratique des problèmes. Sur le plan théorique, vous avez une base de déconnexion entre
=
normalement signifie et ce que cela signifie dans ce cas. En particulier, où l'affectation signifie normalement "en profiter de cette source existante et affecter sa valeur à cette destination", il commence à dire quelque chose de plus, comme "cette source existante, créer une copie de celui-ci, et d'attribuer une valeur à cette destination existant."À partir d'un point de vue pratique, surtout avant les références rvalue ont été inventé, ce qui pourrait avoir un impact significatif sur les performances-la création d'un tout nouvel objet dans le cadre de la copie de A à B est inattendue et souvent assez lent. Si, par exemple, j'ai eu un petit vecteur, et il a attribué à un plus grand vecteur, je m'attends à prendre, tout au plus, le temps de copier les éléments de la petite vecteur plus une (petite) des frais fixes pour ajuster la taille du vecteur de destination. Si au lieu impliqués deux exemplaires, l'un à partir de la source à la température, un autre de temp à destination, et (pire) d'une allocation dynamique de la temporaire de vecteur, mon attente, à propos de la complexité de l'opération serait entièrement détruit. Pour un petit vecteur, le temps pour l'allocation dynamique pourrait facilement être plusieurs fois plus élevé que le temps de copier les éléments.
La seule autre option (ajouté en C++11) serait de revenir référence rvalue. Cela pourrait facilement conduire à des résultats inattendus--enchaînés assignation comme
a=b=c;
pourrait détruire le contenu deb
et/ouc
, ce qui serait tout à fait inattendue.Que les feuilles de retourner une référence normal (pas une référence const, ni une référence rvalue) comme la seule option (raisonnablement) de manière fiable produit de ce que la plupart des gens veulent.
const T &ref = T{} = t;
alors c'est un bancales de référence, indépendamment de savoir sioperator=
retournéT&
ouT const &
. Ironiquement, c'est bien si leoperator=
retourné en valeur!lvalue reference
. Merci pour cela (parce que oui, une référence rvalue est clairement une mauvaise idée ici).C'est en partie parce que de retourner une référence à l'autonomie est plus rapide que de retourner à la valeur, mais en plus, c'est pour permettre à l'origine de la sémantique qui existent dans les types primitifs.
operator=
peuvent être définies afin de retourner tout ce que vous voulez. Vous avez besoin d'être plus précis quant à la nature de ce problème; je soupçonne que vous avez le constructeur de copie utilisationoperator=
en interne et qui provoque un débordement de pile, que le constructeur de copie appelsoperator=
qui devez utiliser le constructeur de copie de retourA
en valeur à l'infini.A&
deA::operator=
est différente dans la plupart des cas.Il n'y a pas d'exigence de la langue de base sur le type de résultat d'un définis par l'utilisateur
operator=
, mais la bibliothèque standard n'ont qu'une telle exigence:C++98 §23.1/3:
C++98 §23.1/4:
Retour une copie par valeur serait encore en charge affectation chaînage comme
a = b = c = 42;
, parce que l'opérateur d'affectation est en droit associatif, c'est analysée commea = (b = (c = 42));
. Mais de retour une copie interdirait pas de sens constructions comme(a = b) = 666;
. Pour une petite classe de retourner une copie pourrait éventuellement être plus efficace, tandis que pour une classe plus large de retour par référence sera généralement plus efficace (et une copie, trop inefficace).Jusqu'à ce que j'ai appris au sujet de la bibliothèque standard d'exigence que j'ai utilisé pour laisser
operator=
retourvoid
, pour plus d'efficacité et pour éviter l'absurdité de soutenir des effets secondaires en fonction de mauvais code.Avec C++11, il est en outre l'exigence de
T&
type de résultat pourdefault
-ing de l'opérateur d'affectation, carC++11 §8.4.2/1: