Inline membre opérateurs vs inline opérateurs C++
Si j'ai deux structures:
struct A
{
float x, y;
inline A operator*(A b)
{
A out;
out.x = x * b.x;
out.y = y * b.y;
return out;
}
}
Et un équivalent struct
struct B
{
float x, y;
}
inline B operator*(B a, B b)
{
B out;
out.x = a.x * b.x;
out.y = a.y * b.y;
return out;
}
Sauriez-vous une raison pour B de l'opérateur* pour compiler tout différemment, ou d'exécuter un plus lent ou plus rapide que l'opérateur* (les actions qui vont à l'intérieur, sur les fonctions doivent être pertinentes)?
Ce que je veux dire, c'est... ce serait de déclarer la ligne de l'opérateur en tant que membre, vs non en tant que membre, toute générique effet sur la vitesse de la fonction elle-même, que ce soit?
J'ai un certain nombre de différentes structures qui suivent actuellement la ligne des membres de l'opérateur de style... Mais je voulais le modifier pour être valide, le code en C, au lieu; donc, avant de me faire ce que je voulais savoir si il y aurait des modifications à la performance/la compilation.
OriginalL'auteur Serge | 2012-05-20
Vous devez vous connecter pour publier un commentaire.
La façon dont vous l'avez écrit, je m'attends à
B::operator*
à courir un peu plus lent. C'est parce que le "sous le capot" de la mise en œuvre deA::operator*
est comme:Donc
A
passe un pointeur vers sa partie gauche de l'argument de la fonction, tandis queB
a à faire une copie de ce paramètre avant l'appel de la fonction. Les deux ont à faire des copies de leur côté droit de paramètres.Votre code serait beaucoup mieux, et probablement à mettre en œuvre même pour
A
etB
, si vous avez écrit à l'aide de références et ilconst
correct:Vous souhaitez retourner des objets, pas de références, puisque les résultats sont effectivement temporaires (vous n'êtes pas de retour une modification de l'objet existant).
Additif
Tout d'abord, les deux impliquent la même déférence lorsque vous avez saisi tous les code. (Rappelez-vous, l'accès à des membres de
this
implique un déréférencement de pointeur.)Mais même alors, il dépend de la façon intelligente de votre compilateur. Dans ce cas, disons qu'il ressemble à votre structure et décide qu'elle ne peut pas le farcir dans un registre parce que c'est un des deux flotteurs, donc il va utiliser des pointeurs pour y accéder. De sorte que le pointeur déréférencé cas (qui est ce que les références de la mise en œuvre comme) est le meilleur que vous allez obtenir. L'assemblée va ressembler à quelque chose comme ceci (c'est de la pseudo-assemblage-code):
C'est en supposant un RISC architecture (dire, BRAS). x86 utilise probablement moins d'étapes mais il est élargi à propos de ce niveau de détail par le décodeur d'instruction de toute façon. Le point étant que tout est fixe décalage déréférence de pointeurs dans des registres, ce qui est à peu près aussi vite qu'il obtiendra. L'optimiseur peut essayer d'être plus intelligent et de mettre en œuvre les objets à travers plusieurs registres, mais ce genre de optimizer est beaucoup plus difficile d'écrire. (Mais j'ai l'intuition qu'un LLVM-type de compilateur/optimiseur pourrait faire l'optimisation facilement si
result
était simplement un objet temporaire qui n'est pas conservé.)Donc, puisque vous êtes à l'aide de
this
, vous avez un implicite de déréférencement de pointeur. Mais que faire si l'objet étaient sur la pile? N'aide pas; pile variables transformer en fixe décalage déréférence le pointeur de pile (ou pointeur de l'image, si elle est utilisée). Donc, vous êtes un déréférencement d'un pointeur quelque part dans la fin, à moins que votre compilateur est assez lumineux pour prendre votre objet et l'étaler sur plusieurs registres.Hésitez pas à passer le
-S
option pourgcc
pour obtenir un démontage de la version finale du code pour voir ce qui se passe réellement dans votre cas.Non, car les deux impliquent un déréférencement (on déréférence le
this
pointeur, l'autre une référence explicite argument, mais le coût est le même).Si le compilateur ne peut prouver qu'un passage par référence/argument est une charge, un seul argument, il peut optimiser le pointeur/référence à un passage par valeur.
OriginalL'auteur Mike DeSimone
Vous devriez vraiment laisser
inline
-ing pour le compilateur.Cela dit, les fonctions définies dans la définition de la classe (comme c'est le cas avec
A
) sontinline
par défaut. Leinline
rédacteur de devis pourA::operator *
est inutile.Le plus intéressant est quand vous avez la fonction de membre de définition en dehors de la définition de la classe. Ici, inline est nécessaire si vous souhaitez fournir une indication pour le compilateur (qui peut ignorer à volonté) que c'est souvent utilisée et les instructions doivent être compilés en ligne au sein de l'appelant.
Lire le C++ FAQ 9.
Rappelez-vous aussi que le compilateur (maddeningly) est autorisé à ignorer
inline
quand elle se sent comme elle. Ainsi, vous pouvez également déclarerinline
non-membre de fonctions commestatic
dans le cas où il fait cela pour vous, si vous n'obtenez pas multiplier défini-symbole des erreurs au moment de la liaison. (Je dis "maddeningly", car cela crée une situation que j'ai touché là où#define
pouvez forcer l'in-lining, tout uninline
fonction ne peut pas, et il s'est avéré que le code à l'aide deinline
est plus grande et a nécessité plus de pile. Personne ne pense à l'embedded gars.)Veuillez noter que j'ai dit "déclarer
inline
non fonctions commestatic
". Lestatic
mot-clé, malheureusement, a sauvagement des significations différentes dans les deux contextes. Mon point était uniquement d'éviter de multiplier défini-symbole des erreurs parce que le compilateur a décidé de ne pas incorporer une non fonction. Aussi, j'ai rencontré ce problème dans la pratique, afin de ne pas tous les compilateurs sont standard conforme à la façon dont vous décrivez.J'ai mal lu. Des excuses. Mon mauvais!
OriginalL'auteur dirkgently
Ici est de savoir comment j'aurais pu écrire la structure:
Pour répondre à la question, oui l'écriture d'un opérateur comme une fonction membre peut être un peu plus rapide dans certaines circonstances, mais pas assez pour faire une différence notable dans votre code.
Quelques remarques:
Jamais à vous soucier d'utiliser le mot-clé inline. L'optimisation des compilateurs
prendre leurs propres décisions à propos de quoi et quoi ne pas inline.
Utilisation de l'initialisation des constructeurs. Le faire parce qu'ils améliorent code
la lisibilité. Mieux dormir en sachant qu'ils peuvent apporter de petits
avantages de performance.
Passer des structs par référence const aussi souvent que possible.
Se concentrer sur l'écriture de code qui a un bon style n'est pas rapide. La plupart du code est
assez vite, et si elle ne l'est pas c'est probablement à cause de quelque chose
boneheaded dans les algorithmes ou de la manipulation de IO.
Certains compilateurs, dans certaines conditions, favoriser les en passant le pointeur "this" autour de par vous inscrire MAIS que voudrais juste dire quelques autres code assembleur près de l'appel de la fonction est un peu plus lent. Donc: ne vous inquiétez pas à ce sujet.
Oh, merci beaucoup!
OriginalL'auteur cdiggins