Je cherche un moyen facile de trouver des variables de membre de classe non initialisées.
Les trouver dans runtime ou compile time est OK.
Actuellement, j'ai un point d'arrêt dans le constructeur de la classe et j'examine les variables de membre une par une.
Si vous utilisez GCC, vous pouvez utiliser l'indicateur -Weffc++
, qui génère des avertissements lorsqu'une variable n'est pas initialisée dans la liste d'initialisation des membres. Ce:
class Foo
{
int v;
Foo() {}
};
Mène à:
$ g++ -c -Weffc++ foo.cpp -o foo.o
foo.cpp: In constructor ‘Foo::Foo()’:
foo.cpp:4: warning: ‘Foo::v’ should be initialized in the member initialization list
Un inconvénient est que -Weffc++
vous avertira également lorsqu'une variable a un constructeur par défaut approprié et que l'initialisation ne serait donc pas nécessaire. Il vous avertira également lorsque vous initialisez une variable dans le constructeur, mais pas dans la liste d'initialisation des membres. Et il met en garde sur de nombreux autres problèmes liés au style C++, tels que les constructeurs de copie manquants. Vous devrez peut-être nettoyer un peu votre code lorsque vous souhaitez utiliser -Weffc++
de manière régulière.
Il y a aussi un bogue qui vous donne toujours un avertissement lors de l'utilisation d'unions anonymes, que vous ne pouvez actuellement pas contourner autrement que de désactiver l'avertissement, ce qui peut être fait avec:
#pragma GCC diagnostic ignored "-Weffc++"
Cependant, dans l’ensemble, j’ai trouvé que -Weffc++
était incroyablement utile pour attraper de nombreuses erreurs C++ courantes.
Valgrind peut vous dire si vous êtes sur Linux.
Valgrind (FREE, sous Linux) et Purify (sous Windows) trouve des variables non initialisées, des pointeurs invalides, etc. en exécutant votre code dans une machine virtuelle spéciale.
Ceci est facile à utiliser et extrêmement puissant; il y aura probablement de nombreux bogues au-delà des variables non initialisées évidentes.
Coverity , Klocwork et Lint peut trouver des variables non initialisées à l'aide d'une analyse de code statique.
cppcheck trouvera ceci, par exemple:
cppcheck my_src_dir --output-file=check.txt --inconclusive --enable=warning
-Wuninitialized
?
(Ceci vérifie seulement si une variable est utilisée non initialisée, c’est-à-dire si
struct Q {
int x, y;
Q() : x(2) {}
int get_xy() const { return x*y; }
};
g ++ avertira uniquement lorsque l'utilisateur appelle get_xy()
sans affecter à y
.)
Visual Studio (MSVC) possède une option de compilateur/sdl (Enable Additional Security Checks) ( http://msdn.Microsoft.com/en-us/library/jj161081.aspx ). Au moment de l'exécution, il:
Effectue l'initialisation du membre de la classe. Initialise automatiquement la classe membres de type pointeur mis à zéro lors de l'instanciation de l'objet (avant l'exécution du constructeur ). Cela permet d’empêcher l’utilisation de données non initialisées associé à des membres de classe que le constructeur ne fait pas explicitement initialiser.
Cela ne vous aidera pas à détecter les variables membres non initialisées au moment de la compilation, mais rend le comportement plus prévisible lorsqu'il se produit au moment de l'exécution. Vous ne devriez pas écrire de code qui repose sur l'activation de cette option, bien sûr.
Si vous utilisez Visual Studio, vous pouvez compiler en mode débogage, arrêter le programme dans le débogueur et rechercher les variables initialisées sur les octets contenant 0xCC (pile) ou 0xCD (tas).
Personnellement, j'investirais dans un outil d'analyse statique pour une approche plus approfondie.
/analyse sur Visual Studio ("Team System")
Clang avec clang-analyse est capable de le faire. Il créera éventuellement un rapport Nice HTML indiquant à quel moment la variable inutilisée est utilisée.
Il faut se méfier! Les options du compilateur proposées ici ne sont ni fiables, ni indépendantes de la version. Prenons l'exemple simple:
class A {
int a;
public:
void mA() {
printf("haha");
++a;
int g = 2/a;
printf("%i\n",g);
}
};
int main() {
A a;
a.mA();
}
Compilé avec g++ -O3 -Weffc++ -Wuninitialized
, cette chose affiche uninitialized
sur les versions de gcc jusqu’à la version 4.6 incluse, et passe heureusement sur les versions 4.7 et 4.8 (testé sur MacPorts). Ensuite, curieusement, si nous retirons la printf("haha");
, 4.7 et 4.8 voient tout à coup uninitialized A::a
. Clang
est un peu mieux, car il attribue en quelque sorte des ordures (au lieu de 0
) aux vars non initialisés, vous voyez ainsi leur effet désastreux plus facilement/plus tôt.
Je n'ai pas eu beaucoup de chance en repérant le A::a
non initialisé ci-dessus avec valgrind
non plus; peut-être que la suggestion suggérant valgrind
pourrait fournir des options appropriées pour détecter cette erreur.
En bout de ligne: excellente question, peu de solutions fiables pour le moment ... (à mon sens).