89 votes

Pourquoi l'opérateur d'affectation de copie doit-il retourner une référence/constante ?

En C++, le concept de retour de référence de l'opérateur d'affectation de copie n'est pas clair pour moi. Pourquoi l'opérateur de copie ne peut-il pas renvoyer une copie du nouvel objet ? De plus, si j'ai la classe A et les suivantes :

A a1(param);
A a2 = a1;
A a3;

a3 = a2; //<--- this is the problematic line

El operator= est défini comme suit :

A A::operator=(const A& a)
{
    if (this == &a)
    {
        return *this;
    }
    param = a.param;
    return *this;
}

4 votes

Il n'y a pas d'exigence de ce genre. Mais si vous voulez vous en tenir au principe de la moindre surprise, vous retournerez A& juste comme a=b est une expression lvalue faisant référence à a en cas a y b sont des ints.

0 votes

@MattMcNabb Merci de me le faire savoir ! Je le ferai

0 votes

Pourquoi ne pouvons-nous pas revenir A* de l'opérateur d'affectation par copie, je suppose que l'affectation par chaînage fonctionnerait toujours correctement. Quelqu'un peut-il m'aider à comprendre les dangers de renvoyer A* s'il y en a.

85voto

Alex Collins Points 111

Un petit éclaircissement sur la raison pour laquelle il est préférable de retourner par référence pour operator= par rapport au rendement par valeur --- comme la chaîne a = b = c fonctionnera correctement si une valeur est retournée.

Si vous renvoyez une référence, le travail effectué est minime. Les valeurs d'un objet sont copiées dans un autre objet.

Cependant, si vous retournez par valeur pour operator= vous appellerez un constructeur et un destructeur à CHAQUE fois que l'opérateur d'affectation sera appelé !

Donc, donné :

A& operator=(const A& rhs) { /* ... */ };

Ensuite,

a = b = c; // calls assignment operator above twice. Nice and simple.

Mais,

A operator=(const A& rhs) { /* ... */ };

a = b = c; // calls assignment operator twice, calls copy constructor twice, calls destructor type to delete the temporary values! Very wasteful and nothing gained!

En somme, il n'y a rien à gagner à retourner par valeur, mais beaucoup à perdre.

( Note : Il ne s'agit pas d'aborder les avantages d'avoir l'opérateur d'assignation qui renvoie une lvalue. Lisez les autres articles pour savoir pourquoi c'est préférable).

0 votes

Ce que je trouve ennuyeux, c'est que vous êtes autorisé à retourner un type stupide. Je pense qu'on devrait appliquer la ref non-const du type... Bien que pour supprimer la fonction, ce qu'elle renvoie n'a pas beaucoup d'importance.

82voto

Michael Burr Points 181287

Strictement parlant, le résultat d'un opérateur d'affectation par copie n'a pas besoin de retourner une référence, bien que pour imiter le comportement par défaut du compilateur C++, il devrait retourner une référence non-const à l'objet auquel il est affecté (un opérateur d'affectation par copie généré implicitement retournera une référence non-const - C++03 : 12.8/10). J'ai vu pas mal de code qui retourne void à partir de surcharges d'assignation de copie, et je ne me rappelle pas quand cela a causé un problème sérieux. Retour à void empêchera les utilisateurs de "chaîner les tâches" ( a = b = c; ), et empêchera d'utiliser le résultat d'une affectation dans une expression de test, par exemple. Bien que ce genre de code soit loin d'être inconnu, je ne pense pas non plus qu'il soit particulièrement courant - surtout pour les types non primitifs (à moins que l'interface d'une classe ne prévoie ce genre de tests, comme pour les iostreams).

Je ne vous recommande pas de le faire, je vous signale simplement que c'est autorisé et que cela ne semble pas causer beaucoup de problèmes.

Ces autres questions de l'OS sont liées (probablement pas tout à fait des doublons) et contiennent des informations/opinions qui pourraient vous intéresser.

0 votes

J'ai trouvé utile de retourner void sur l'opérateur d'affectation lorsque j'avais besoin d'empêcher la destruction automatique des objets lorsqu'ils descendaient de la pile. Pour les objets ref-comptés, vous ne voulez pas que les destructeurs soient appelés quand vous ne les connaissez pas.

8voto

msw Points 25319

Parce que la sémantique du C - et donc du C++ - exige que la valeur de l'opérateur d'assignation soit une valeur Valeur l pour permettre (entre autres) :

a = b = 0;

Les références ont cette propriété, les valeurs r ne l'ont pas.

6voto

Puppy Points 90818

C'est en partie parce que renvoyer une référence à self est plus rapide que de renvoyer par valeur, mais en plus, c'est pour permettre la sémantique originale qui existe dans les types primitifs.

0 votes

Je ne vais pas voter contre, mais j'aimerais souligner que le retour par valeur n'aurait aucun sens. Imaginez (a = b = c) si (a = b) retournait 'a' par valeur. Votre dernier point est très légitime.

5 votes

Vous obtiendriez (a = (b = c)), je crois, ce qui produirait toujours le résultat escompté. Ce n'est que si vous faites (a = b) = c qu'il y aurait rupture.

4voto

MSN Points 30386

operator= peut être défini pour retourner ce que vous voulez. Vous devez être plus précis quant à la nature du problème ; je soupçonne que le constructeur de copie utilise operator= en interne et cela provoque un débordement de pile, car le constructeur de la copie appelle operator= qui doit utiliser le constructeur de copie pour retourner A par valeur à l'infini.

0 votes

Ce serait une mise en œuvre boiteuse (et inhabituelle) du copy-ctor. La raison de retourner A& de A::operator= est différent dans la plupart des cas.

0 votes

@jpalecek, je suis d'accord, mais étant donné le post original et le manque de clarté dans l'énoncé du problème réel, il est plus probable que l'exécution de l'opérateur d'assignation résulte en un stackoverflow dû à une récursion infinie. S'il y a une autre explication à cette question, j'aimerais la connaître.

0 votes

@MSN Je ne sais pas si c'était son problème ou pas. Mais il est certain que votre message ici a résolu mon problème, +1 pour cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X