Pro / con: Initialisation d’une variable dans une instruction conditionnelle

En C ++, vous pouvez initialiser une variable dans une instruction if, comme ceci:

if (CThing* pThing = GetThing()) { } 

Pourquoi considérer ce bon ou mauvais style? Quels sont les avantages et les inconvénients?

Personnellement, j’aime ce style car il limite la scope de la variable pThing et ne peut donc pas être utilisé accidentellement lorsqu’il est NULL. Cependant, je n’aime pas que vous ne puissiez pas faire ça:

 if (CThing* pThing = GetThing() && pThing->IsReallySomeThing()) { } 

S’il y a un moyen de faire fonctionner ce qui précède, postez-le. Mais si ce n’est pas possible, j’aimerais quand même savoir pourquoi.

Question empruntée à partir d’ici, sujet similaire mais PHP.

L’important est qu’une déclaration en C ++ ne soit pas une expression.

 bool a = (CThing* pThing = GetThing()); // not legit!! 

Vous ne pouvez pas faire à la fois une déclaration et une logique booléenne dans une instruction if. La spécification du langage C ++ autorise spécifiquement une expression ou une déclaration.

 if(A *a = new A) { // this is legit and a is scoped here } 

Comment savoir si un est défini entre un terme et un autre dans une expression?

 if((A *a = new A) && a->test()) { // was a really declared before a->test? } 

Mordez la balle et utilisez un if interne. Les règles de scope sont utiles et votre logique est explicite:

 if (CThing* pThing = GetThing()) { if(pThing->IsReallySomeThing()) { } } 

Sur les avantages:

Il est toujours recommandé de définir les variables dès que vous en avez besoin, pas une ligne auparavant. C’est pour une meilleure lisibilité de votre code, car on peut dire ce qu’est CThing sans faire défiler et rechercher où il a été défini.

En réduisant également la scope à un bloc loop / if, la variable n’est plus référencée après l’exécution du bloc de code, ce qui en fait un candidat pour Garbage Collection (si le langage prend en charge cette fonctionnalité).

 if (CThing* pThing = GetThing()) 

C’est un mauvais style , car à l’intérieur du if vous ne fournissez pas une expression booléenne. Vous fournissez un CThing* .

 CThing* pThing = GetThing(); if (pThing != NULL) 

C’est bon style.

Une des raisons pour lesquelles je ne le fais pas normalement est à cause du bogue commun d’un raté ‘=’ dans un test conditionnel. J’utilise des peluches avec les erreurs / avertissements réglés pour les attraper. Il va ensuite crier sur toutes les assignations à l’intérieur de conditionnels.

À titre d’exemple, certains des anciens fournisseurs de logiciels Microsoft C ++ (Visual Studios 6 et .NET 2003, je pense) ne suivent pas tout à fait la règle de scope dans certains cas.

 for(int i = 0; i > 20; i++) { // some code } cout << i << endl; 

Je devrais être hors de scope, mais c'était / code valide. Je crois que cela a été joué comme une fonctionnalité, mais à mon avis, c'est simplement la non-conformité. Ne pas adhérer aux normes est mauvais. Tout comme un développeur Web sur IE et Firefox.

Est-ce que quelqu'un avec VS peut vérifier et voir si c'est toujours valide?

Cela ne devrait pas fonctionner en C ++, même s’il prend en charge l’ évaluation des courts-circuits . Peut -être n’essayez pas ce qui suit:

 if ((CThing* pThing = GetThing()) && (pThing->IsReallySomeThing())) { } 

euh .. voir la réponse de Wesley Tarle

Vous pouvez également inclure l’affectation dans un ensemble supplémentaire de () pour empêcher le message d’avertissement.

Je vois cela comme un peu dangereux. Le code ci-dessous est beaucoup plus sûr et les accolades englobantes limiteront toujours la scope de pThing comme vous le souhaitez.

Je suppose que GetThing () renvoie parfois NULL, raison pour laquelle j’ai placé cette clause amusante dans l’instruction if (). Cela empêche IsReallySomething () d’être appelée sur un pointeur NULL.

 { CThing *pThing = GetThing(); if(pThing ? pThing->IsReallySomeThing() : false) { // Do whatever } } 

Notez également que si vous écrivez du code C ++, vous souhaitez que le compilateur avertisse de “=” dans une instruction conditionnelle (qui ne fait pas partie d’une déclaration) une erreur.

C’est une bonne pratique de codage. Cependant, les personnes qui ne viennent pas d’un contexte de codage de bas niveau seraient probablement en désaccord.

Tant de choses. Tout d’abord, des indicateurs nus. S’il vous plaît évitez-les par tous les moyens. Utilisez des références, facultatif, unique_ptr, shared_ptr. En dernier recours, écrivez votre propre classe qui traite de la propriété d’un pointeur et de rien d’autre.

Utilisez une initialisation uniforme si vous pouvez avoir besoin de C ++ 11 (C ++ 14 est préférable pour éviter les défauts de C ++ 11): – cela évite la confusion = vs == et il est plus ssortingct de vérifier les arguments s’il en existe.

 if (CThing thing {}) { } 

Assurez-vous de mettre en œuvre l’ operator bool pour obtenir une conversion prévisible de CThing en bool. Cependant, gardez à l’esprit que les autres lecteurs du code ne verraient pas l’ operator bool immédiatement operator bool . Les appels de méthodes explicites sont généralement plus lisibles et rassurants. Si vous pouvez avoir besoin de C ++ 17, utilisez la syntaxe d’initialisation.

 if (CThing thing {}; thing.is_good()) { } 

Si C ++ 17 n’est pas une option, utilisez une déclaration ci-dessus si, comme d’autres l’ont suggéré.

 { CThing thing {}; if (thing.is_good()) { } }