Bonjour,
J'ai une classe A :
Lequel des deux constructeurs et le plus rapide ?Code:
1
2
3
4
5
6
7
8 class A { private: double _d; public: A(double a) { _d = a } A(const double & a); { _d = a; } };
Merci.
Version imprimable
Bonjour,
J'ai une classe A :
Lequel des deux constructeurs et le plus rapide ?Code:
1
2
3
4
5
6
7
8 class A { private: double _d; public: A(double a) { _d = a } A(const double & a); { _d = a; } };
Merci.
Aucun, les deux seront compil�s de la m�me mani�re la plus optimale, vu qu'il s'agit d'un type primitif, sauf sur une architecture mal fichue.
Cela, gr�ce � la r�gle du "as if", qui dit qu'un compilateur peut faire ce qu'il veut, tant que tu ne vois pas la diff�rence avec les exigences de la norme.
De toute fa�on, le plus rapide sera normalement le suivant:
Ce constructeur aura lui l'avantage de ne pas initialiser _d avant de le r�affecter.Code:A(double const& a) : _d(a) {}
dans ce cas :
b est plus rapide que a ? on �vite une recopie ?Code:
1
2
3
4
5
6 int fonction() { return 2;} int main() { int a = function(); int & b = function(); }
�a ne compilera pas car une r�f�rence ne peut pas �tre initialis�e avec une rvalue (mais une r�f�rence constante si (allongement de la dur�e de vie et des probl�mes si mal utilis�e)).
Mais sinon, le compilateur optimisera avec une �lision (voir RVO).
Ca, c'est tout un programme, qui d�pendra essentiellement de la signature complete de function et de l'origine de la valeur qu'elle renvoie...
De mani�re g�n�rale : si function renvoie une valeur, nous avons la certitude que int a = function() fonctionnera, par contre, int & b = function() aura un probl�me car b sera une r�f�rence invalide (car la dur�e de vie de la variable renvoy�e par function ne sera pas �largie � une variable d�clar�e dans la fonction appelante).
D'un autre cot�, function pourrait renvoyer une r�f�rence. Mais il faut alors voir quelle est l'origine de la variable qui est renvoy�e par r�f�rence. S'il s'agit d'une r�f�rence sur une variable propre � function proche de
les deux codes poseront probl�mes car la r�f�rence est invalid�e par la destruction de la variable qui survient lorsque l'on quitte la fonction.Code:
1
2
3
4
5 double /*const*/ & function(){ double d; /* ... */ return d; // oupppssss... }
Par contre, si la r�f�rence renvoy�e est issue "d'ailleurs" sous une forme qui pourrait �tre proche de
on pourra avoir quelque chose de valide aussi bien pour la valeur a que pour la r�f�rence b. Et, a priori, b sera alors plus rapide parce qu'il n'y a pas copie.Code:
1
2
3
4 double & function (double & d){ /* ... */ return d; }
Par contre, il n'y a pas de sens � s'inqui�ter des �ventuelles pertes de performances dues � la copie d'une variable de type primtif par rapport au passage par r�f�rence, car il n'y a aucun avantage mesurable (la copie des type primitifs est tr�s rapide, et une r�f�rence est repr�sent�e au niveau du code ex�cutable, par une adresse, qui devra de toutes fa�on �tre donn�e et qui prendra autant de temps � �tre �crite en m�moire que ce qu'un double peut n�cessiter pour �tre copi�).
L'id�e est donc, pour les types primitifs et / ou les structures dont la taille est plus petite qu'un ptr_t, de les manipuler syst�matiquement par valeur, sauf s'il s'agit de les transmettre � une fonction qui devra modifier la valeur d'origine et, � ce moment l�, de les passer par r�f�rence non constante.
Pour les types de taille plus importante, la r�gle est de les transmettre syst�matiquement par r�f�rence et de rendre la r�f�rence constante si la variable d'origine ne doit pas �tre modifi�e par la fonction appel�e.
Par contre, lorsqu'il s'agit de renvoyer ces donn�e en sortie de fonction, il faudra s'assurer que la dur�e de vie de l'�l�ment renvoy� sera suffisante. Ce parfois le cas, parfois pas ;)
Justement, non, cela compilera...
L'�l�ment renvoy� par une fonction est syst�matiquement une... lvalue :P. Les deux possibilit�s compileront donc et les deux possibilit�s subiront �ventuellement les m�mes probl�mes en fonction de ce qui est r�ellement renvoy� par function :aie:
Au temps pour moi, je dis une �normit�.
double & b = function(); compilera bien, pour autant que la const-correctness soit respect�e. La raison en est que le compilateur sait se trouver � droite de l'op�rateur d'affectation et qu'il s'attend donc � trouver... une rvalue (qui, basiquement, signifie "quelque chose susceptible de prendre place � droite de l'op�rateur d'affectation" ;)).
La valeur renvoy�e par une fonction peut, quoi qu'il arrive, effectivement prendre place � droite de l'op�rateur d'affectation et le compilateur n'a donc aucune raison de refuser cette affectation.
Par contre, le fait que le code compile ne signifie absolument pas qu'il s'ex�cutera sans probl�me :aie:. Et le fait est que le compilateur ne dispose que de la signature de la fonction appel�e pour se faire un id�e de "ce qui fonctionnera" et de "ce qui n'ira pas".
Le probl�me, c'est que ce n'est pas assez pour pouvoir se faire une id�e :aie:. Il y a en effet trois solutions :
- La fonction renvoie une valeur : le compilateur pourrait �ventuellement nous indiquer que nous affectons un temporaire � notre r�f�rence. Mais il ne le fera que sous la forme d'un avertissement.
- La fonction renvoie une de ses variables propres sous la forme d'une r�f�rence : la r�f�rence est invalide, le compilateur peut indiquer que la fonction appel�e renvoie une r�f�rence sur un temporaire, mais ce n'est encore qu'un avertissement.
- La fonction renvoie un argument qu'elle a re�u sous la forme d'une r�f�rence ou un membre de la classe au d�part duquel la fonction a �t� appel�e : il n'y a aucun probl�me et tout va bien... Si ce n'est que c'est le genre d'information qui n�cessiterait l'analyse du code de la fonction appel�e pour pouvoir s'en assurer. Et le compilateur n'est, a priori, pas �quip� pour faire cette v�rification au niveau de la fonction appelante :P
Donc, oui, il y a toujours un manque de garantie quant au fait que la r�f�rence soit bel et bien valide, mais cela n'occasionnera, au mieux, qu'un avertissement de la part du compilateur avec comme r�sultat le fait que seule des options de compilations particuli�rement strictes (je pense, par exemple, � l'option -werror sous gcc) occasionneront r�ellement une erreur de compilation ;)
Donc j'ai bien le droit de faire :
Comme j'ai le droit de faire :Code:
1
2 (const?) objet & A = construire_objet(); int value = A.get_value();
Code:int value = construire_objet().get_value();
La r�ponse tient en deux mots : oui mais :aie:
Oui, tu as le droit de le faire dans le sens o� le compilateur n'y verra aucune objection.
Mais, pour que A soit une r�f�rence valide, il faut:
- que construire_objet() renvoie une r�f�rence
- que la r�f�rence renvoy�e par construire_objet fasse r�f�rence � un objet qui continue � exister en dehors de cette fonction (autrement dit, que la r�f�rence renvoy�e par construire_objet() soit valide)
Et �a, c'est tr�s loin d'�tre gagn� :aie:
Il est possible de se donner les moyen de garantir que ce sera le cas (en pla�ant l'objet cr�� dans une collection dont on sait qu'elle continuera d'exister en dehors de construire_objet, par exemple), mais, de mani�re g�n�rale, il faut vraiment voir ce que fait exactement la fonction appel�e (construire_objet() en l'occurrence) pour pouvoir te dire si la r�f�rence renvoy�e par cette fonction est valide ou non.
On va donc dire : on peut le faire (c'est l�gal en C++), mais, a priori, il y a de fortes chances pour que cela pose probl�me (du moins, sans avoir un exemple pr�cis de ce que fait la fonction appel�e pour initialiser ta r�f�rence-