Prolonge .
Je pensais que j'étais cool quand j'ai fait quelque chose comme:
bool hasParent () { renvoie ce-> parentNode; }
Même avec un casting (bool), l'avertissement ne disparaît toujours pas.
Où this-> parentNode est NULL lorsqu'il n'y a pas de nœud parent.
Mais je reçois:
avertissement C4800: 'Node *': forcer la valeur à bool 'true' ou 'false' (avertissement de performance)
Quel est le problème, yo? Pourquoi est-ce un avertissement de performances? Je pensais qu'il serait plus efficace de ne pas écrire quelque chose comme:
bool hasParent () { if (this-> parentNode) return true; else retourne faux; }
Mais la deuxième version ne génère aucun avertissement et le compilateur semble beaucoup plus heureux. Quel est le plus rapide?
Il y a une discussion sur Microsoft Connect à ce sujet ( Quelle est l'implication des performances de la conversion en bool en C++? ). L'exemple donné à Microsoft est:
$ cat -n t.cpp && cl -c -W3 -O2 -nologo -Fa t.cpp
1 bool f1 (int i)
2 {
3 return i & 2;
4 }
5
6 bool f2 (int i)
7 {
8 const bool b = i & 2;
9 return b;
10 }
11
12 bool f3 (int i)
13 {
14 const bool b = 0 != (i & 2);
15 return b;
16 }
t.cpp
t.cpp(3) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
t.cpp(8) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
Et la réponse de Microsoft (du développeur responsable de l'avertissement) est:
Cet avertissement est étonnamment utile et a trouvé un bogue dans mon code hier. Je pense que Martin prend "l'avertissement de performance" hors de son contexte.
Il ne s'agit pas du code généré, il s'agit de savoir si le programmeur a signalé ou non l'intention de changer une valeur de int en bool. Il y a une pénalité pour cela, et l'utilisateur a le choix d'utiliser "int" au lieu de "bool" de manière cohérente (ou plus probablement vice versa) pour éviter le codegen "boolifying". L'avertissement est supprimé dans le troisième cas ci-dessous car il a clairement signalé son intention d'accepter la transition int-> bool.
C'est un vieil avertissement et peut avoir survécu à son objectif, mais il se comporte comme prévu ici
Donc, fondamentalement, le développeur MS semble dire que si vous voulez "convertir" un int
en bool
, vous devriez le faire plus correctement en utilisant "return this->parentNode != 0
"au lieu d'une conversion implicite ou explicite.
Personnellement, je serais intéressé d'en savoir plus sur le type de bugs que l'avertissement révèle. Je pense que cet avertissement n'aurait pas beaucoup de valeur.
Le fait que la conversion en bool
ne fasse pas disparaître l'avertissement par conception :
La conversion de l'expression en type bool ne désactivera pas l'avertissement, ce qui est voulu par la conception même du produit.
Je recommanderais l'approche recommandée par la description MSDN de l'avertissement C4800:
return this->parentNode != NULL;
cela indique clairement que vous renvoyez true
si parentNode
n'est pas un pointeur nul et false
si parentNode
est un pointeur nul.
Le compilateur doit générer du code supplémentaire pour convertir un pointeur en bool. Il s'agit essentiellement d'une comparaison avec zéro et de définir le résultat sur un sinon sur zéro.
00000000004005e0 <_Z4testPv>:
bool test(void* adr) {
4005e0: 48 85 ff test %rdi,%rdi
4005e3: 0f 95 c0 setne %al
return adr;
}
4005f8: c3 retq
Ce n'est pas directement visible depuis la source, donc le compilateur pense que c'est quelque chose dont l'utilisateur devrait être averti.
Pourquoi est-ce un avertissement de performances?
Le compilateur tourne ceci:
bool hasParent()
{
return this->parentNode;
}
dans:
bool hasParent()
{
return this->parentNode != 0;
}
Cela prend environ n cycle d'horloge de plus que ce à quoi vous pourriez vous attendre en regardant le code. C'est une différence de performance insignifiante.
Je pense qu'il vaut mieux écrire le != 0
explicitement de toute façon, car cela rend le code plus clair ainsi que la désactivation de l'avertissement.
Il serait plus efficace d'écrire:
bool hasParent()
{
return this->parentNode != NULL;
}
Je suis sûr que cela dépend du compilateur
De manière réaliste, je pense qu'ils optimiseraient la même chose, vous pouvez également essayer de faire ceci:
return this->parentNode != 0;