Bonjour,
Cette technique présentée par Medinoc est "assez" vielle (présentée en 2009 sur C++Next et probablement bien plus ancienne que ça). Son seule fondement est d'éviter une copie (et donc potentiellement gagner en performance) dans le cas où l’affection est faite depuis un temporaire.
Cette technique n'est pas toujours applicable (typiquement pour les opérateurs binaires, le gain de performance n'est pas évident (*)), mais dans ce cas il y a certitude que ça ne pourra être qu'un gain (éventuellement nul, mais ça ne sera pas une perte).
On répète en effet inlassablement que
On pourrait objecter que la façon décrite par Medinoc est aussi idiomatique pour certain codeur :
That realization leads us directly to this guideline:
Guideline: Don’t copy your function arguments. Instead, pass them by value and let the compiler do the copying.
At worst, if your compiler doesn’t elide copies, performance will be no worse. At best, you’ll see an enormous performance boost.
(Dave Abrahams)
Ce constat nous conduit directement à ce conseil :
Conseil: Ne copiez pas les arguments de votre fonction. A la place, passer les par valeur et laissez le compilateur faire la copie.
Au pire, si votre compilateur n'élide pas les copies, la performance ne sera pas pire. Au mieux, vous obtiendrez un énorme gain de performance.
(traduction libre)
Bien entendu l'article, et même la série, est plus complète que ça et d'autre cas doivent être traités (**). Cependant dans le cas de l'opérateur d'affectation, le conseil s'applique parfaitement.
Donc pour tes questions, dans l'ordre, mon avis est :
- Oui, pour obtenir les meilleurs performances possible. Ce n'est pas contraignant niveau écriture, il n'y a donc pas de raisons de s'en priver, quelque soit le gain, AMA.
- J'ai un peu de mal à comprendre le sens de cette question. Que tu fasses la copie implicitement ou explicitement, c'est bien toi codeur qui en prend la décision. Une solution ou l'autre (en supposant que tu puisses écrire les deux) n'impactent pas la façon dont la fonction sera utilisable.
- Oui, profiter de l’élision proposée par le compilateur.
(*) Pour deux raisons, liés au retour, qui est un nouvel objet, et le caractère binaire et donc de priorité d'opérateur.
(**) Le premier point étant lorsque la fonction retourne aussi un objet du même type que le paramètre. L'objectif serait de profiter de deux élisions. La technique suggéré étant d'utiliser un swap :
1 2 3 4 5 6 7 8 9 10 11
|
A foo(A a)
{
using std::swap;
A r;
//stuff
swap(a,r);
//stuff
return r;
} |
J'avouerais ne pas avoir tester si le compilateur est bel et bien capable d'effectuer les deux élisions avec un tel code.
PS: En C++11, et si l'on écrit autre chose qu'un opérateur d'affectation par copie, la donne peut légèrement changer selon la façon dont l'on veut profiter de la move semantic.
Partager