Les règles de base C ++ ont la règle ES.20: toujours initialiser un objet .
Évitez les erreurs used-before-set et leur comportement indéfini associé. Évitez les problèmes de compréhension de l'initialisation complexe. Simplifier le refactoring.
Mais cette règle ne permet pas de trouver des bugs, elle ne fait que les cacher.
Supposons qu'un programme ait un chemin d'exécution dans lequel il utilise une variable non initialisée. C'est un bug. Le comportement non défini mis à part, cela signifie également que quelque chose s'est mal passé et que le programme ne répond probablement pas aux exigences de son produit. Lorsqu'il sera déployé en production, il peut y avoir une perte d'argent, voire pire.
Comment pouvons-nous filtrer les bugs? Nous écrivons des tests. Cependant, les tests ne couvrent pas 100% des chemins d'exécution et ne couvrent jamais 100% des entrées du programme. Plus que cela, même un test couvre un chemin d’exécution défectueux - il peut toujours réussir. Après tout, c'est un comportement indéfini, une variable non initialisée peut avoir une valeur quelque peu valide.
Mais en plus de nos tests, nous avons les compilateurs qui peuvent écrire quelque chose comme 0xCDCDCD dans des variables non initialisées. Cela améliore légèrement le taux de détection des tests.
Mieux encore, il existe des outils comme Address Sanitizer, qui capturera toutes les lectures d'octets mémoire non initialisés.
Enfin, il existe des analyseurs statiques, qui peuvent consulter le programme et indiquer qu’il existe une lecture avant définition sur ce chemin d’exécution.
Nous disposons donc de nombreux outils puissants, mais si nous initialisons la variable, les assainissants ne trouvent rien .
int bytes_read = 0;
my_read(buffer, &bytes_read); // err_t my_read(buffer_t, int*);
// bytes_read is not changed on read error.
// It's a bug of "my_read", but detection is suppressed by initialization.
buffer.shrink(bytes_read); // Uninitialized bytes_read could be detected here.
// Another bug: use empty buffer after read error.
use(buffer);
Il existe une autre règle: si l’exécution d’un programme rencontre un bogue, il doit disparaître le plus tôt possible. Inutile de le garder en vie, écrasez-le, envoyez-le aux ingénieurs pour enquête.
L'initialisation de variables inutilement a l'effet inverse - le programme est maintenu en vie, alors qu'il aurait déjà une erreur de segmentation autrement.
bytes_read
n’est pas modifiée (donc maintenue à zéro), pourquoi s’agit-il d’un bogue? Le programme pourrait toujours continuer de manière saine tant qu'il ne s'attend pas implicitement àbytes_read!=0
après. Les désinfectants ne se plaignent donc pas. D'un autre côté, quand ilbytes_read
n'est pas initialisé au préalable, le programme ne pourra pas continuer normalement, donc ne pas initialiser introduit enbytes_read
fait un bogue qui n'y était pas auparavant.\0
celui-ci, c'est un buggy. S'il est documenté de ne pas traiter cela, votre code d'appel est bogué. Si vous corrigez votre code d'appel à vérifierbytes_read==0
avant de l'utiliser, vous êtes de retour à votre point de départ: votre code est bogué si vous ne l'initialisez pasbytes_read
, sans danger si vous le faites. ( Habituellement, les fonctions sont supposées remplir leurs paramètres de sortie même en cas d'erreur : ce n'est pas vraiment le cas. Très souvent, les sorties sont laissées seules ou non définies.)err_t
rendu parmy_read()
? S'il y a un bogue n'importe où dans l'exemple, c'est tout.Réponses:
Votre raisonnement va mal sur plusieurs comptes:
bytes_read
ait la valeur10
qu'il a la valeur0xcdcdcdcd
.L’idée derrière les instructions pour toujours initialiser les variables est de permettre à ces deux situations
La variable contient une valeur utile dès le tout début de son existence. Si vous combinez cela avec le guidage pour déclarer une variable uniquement lorsque vous en avez besoin, vous pouvez éviter que les futurs programmeurs de maintenance ne tombent dans le piège de commencer à utiliser une variable entre sa déclaration et la première affectation, où la variable existerait mais ne serait pas initialisée.
La variable contient une valeur définie que vous pouvez tester ultérieurement, pour indiquer si une fonction similaire
my_read
a mis à jour la valeur. Sans initialisation, vous ne pouvez pas savoir sibytes_read
une valeur est réellement valide, car vous ne pouvez pas savoir avec quelle valeur elle a commencé.la source
= 0;
. Le but de l’avis est de déclarer la variable au point où vous aurez une valeur utile et d’affecter cette valeur immédiatement. Ceci est clairement expliqué dans les règles suivantes ES21 et ES22 qui suivent. Ces trois devraient tous être compris comme travaillant ensemble; pas en tant que règles individuelles sans rapport.Vous avez écrit "cette règle ne permet pas de rechercher des bogues, elle les cache seulement" - eh bien, l'objectif de la règle n'est pas d'aider à trouver des bogues, mais de les éviter . Et lorsqu'un bug est évité, rien n'est caché.
Examinons le problème à l'aide de votre exemple: supposons que la
my_read
fonction ait le contrat écrit pour initialiserbytes_read
en toutes circonstances, mais pas en cas d'erreur. Elle est donc défectueuse, du moins dans ce cas. Votre intention est d'utiliser l'environnement d'exécution pour afficher ce bogue en n'initialisant pas lebytes_read
paramètre en premier. Tant que vous savez avec certitude qu’un désinfectant d’adresse est en place, c’est un moyen efficace de détecter un tel bogue. Pour corriger le bogue, il faut changer lamy_read
fonction en interne.Mais il existe un point de vue différent, qui est au moins également valable: le comportement fautif ne provient que de la combinaison non initialisation
bytes_read
préalable et appelantmy_read
après (avec l'attentebytes_read
est initialisée ensuite). Il s'agit d'une situation qui se produira souvent dans des composants du monde réel lorsque la spécification écrite d'une fonction similairemy_read
n'est pas claire à 100%, voire erronée sur le comportement en cas d'erreur. Cependant, tantbytes_read
que l'initialisation a été effectuée à zéro avant l'appel, le programme se comporte de la même manière que si l'initialisation avait été effectuée à l'intérieurmy_read
. Il se comporte donc correctement. Dans cette combinaison, il n'y a pas de bogue dans le programme.Donc, ma recommandation qui en découle est la suivante: utilisez l’approche de non-initialisation uniquement si
Ce sont des conditions que vous pouvez généralement organiser dans le code de test , pour un environnement d'outillage spécifique.
Cependant, dans le code de production, il est préférable d’initialiser au préalable une telle variable. C’est l’approche la plus défensive, qui évite les bugs si le contrat est incomplet ou erroné, ou si le correcteur d’adresse ou des mesures de sécurité similaires ne sont pas activés. Et la règle "crash-early" s'applique, comme vous l'avez correctement écrit, si l'exécution du programme rencontre un bogue. Mais lorsque l’initialisation d’une variable au préalable signifie qu’il n’ya rien d’erreur, il n’est pas nécessaire d’arrêter l’exécution.
la source
Toujours initialiser vos variables
La différence entre les situations que vous envisagez est que le cas sans initialisation entraîne un comportement indéfini , tandis que le cas où vous avez pris le temps de l'initialiser crée un bogue bien défini et déterministe . Je ne saurais dire à quel point ces deux cas sont extrêmement différents.
Prenons un exemple hypothétique qui aurait pu arriver à un employé hypothétique participant à un programme de simulations hypothétiques. Cette équipe hypothétique essayait hypothétiquement de faire une simulation déterministe pour démontrer que le produit qu'elle vendait hypothétiquement répondait à des besoins.
D'accord, je vais m'arrêter avec le mot injections. Je pense que vous comprenez l'idée ;-)
Dans cette simulation, il y avait des centaines de variables non initialisées. Un développeur a exécuté valgrind sur la simulation et a remarqué plusieurs erreurs de type "branche sur une valeur non initialisée". "Hmm, cela semble causer un non-déterminisme, ce qui rend difficile la répétition de tests lorsque nous en avons le plus besoin." Le développeur s'est adressé à la direction, mais la direction avait un calendrier très serré et elle ne pouvait pas épargner de ressources pour détecter ce problème. "Nous finissons par initialiser toutes nos variables avant de les utiliser. Nous avons de bonnes pratiques de codage."
Quelques mois avant la livraison finale, lorsque la simulation est en mode de désabonnement complet et que toute l'équipe est prête à achever toutes les tâches promises par la direction dans un budget qui, comme chaque projet jamais financé, était trop petit. Quelqu'un a remarqué qu'ils ne pouvaient pas tester une fonctionnalité essentielle car, pour une raison quelconque, la sim déterministe ne se comportait pas de manière déterministe pour déboguer.
L’ensemble de l’équipe a peut-être été arrêté et a passé la plus grande partie de sa peine, pendant deux mois, à peindre l’ensemble de la base de code de la simulation pour réparer les erreurs de valeur non initialisées au lieu de mettre en œuvre et de tester les fonctionnalités. Il va sans dire que l'employé a ignoré les "Je vous l'avais bien dit" et a directement aidé d'autres développeurs à comprendre ce que sont des valeurs non initialisées. Curieusement, les normes de codage ont été modifiées peu de temps après cet incident, encourageant les développeurs à toujours initialiser leurs variables.
Et c'est le coup d'avertissement. C'est la balle qui a frôlé le nez. Le problème est loin beaucoup plus insidieux que vous ne le pensez même.
L'utilisation d'une valeur non initialisée est un "comportement indéfini" (à l'exception de quelques cas tels que
char
). Un comportement indéfini (ou UB en abrégé) est tellement insensé et complètement mauvais pour vous, que vous ne devriez jamais jamais croire qu'il est meilleur que l'alternative. Parfois, vous pouvez identifier que votre compilateur particulier définit l'UB, puis son utilisation en toute sécurité, mais sinon, un comportement indéfini correspond à "tout comportement du compilateur." Cela peut faire quelque chose que vous appelleriez «sain d’esprit», comme avoir une valeur non spécifiée. Il peut émettre des codes opération non valides, ce qui pourrait entraîner la corruption de votre programme. Cela peut déclencher un avertissement au moment de la compilation ou même être considéré par le compilateur comme une erreur.Ou il peut ne rien faire du tout
Mon canari dans la mine de charbon pour UB est un cas d'un moteur SQL que j'ai lu. Pardonnez-moi de ne pas le lier, j'ai échoué à trouver l'article à nouveau. Il y avait un problème de dépassement de tampon dans le moteur SQL lorsque vous passiez une taille de tampon plus grande à une fonction, mais uniquement sur une version particulière de Debian. Le bogue a été consigné consciencieusement et exploré. La partie amusante était: le dépassement de tampon a été vérifié . Il y avait du code pour gérer le dépassement de tampon en place. Cela ressemblait à ceci:
J'ai ajouté plus de commentaires dans mon rendu, mais l'idée est la même. Si vous
put + dataLength
enroulez, il sera plus petit que leput
pointeur (ils avaient des vérifications de compilation pour s'assurer que unsigned int était de la taille d'un pointeur, pour les curieux). Si cela se produit, nous savons que les algorithmes de mémoire tampon en anneau standard peuvent être perturbés par ce débordement. Nous renvoyons donc 0. Ou le faisons-nous?En fin de compte, le débordement sur les pointeurs n'est pas défini en C ++. Comme la plupart des compilateurs traitent les pointeurs comme des entiers, nous nous retrouvons avec des comportements de débordement d'entier typiques, qui se trouvent être le comportement que nous souhaitons. Cependant, il s’agit d’ un comportement indéfini, ce qui signifie que le compilateur est autorisé à faire tout ce qu’il veut.
Dans le cas de ce bogue, Debian est arrivé à choisir d'utiliser une nouvelle version de gcc qu'aucun des autres grandes saveurs de Linux a mis à jour dans leurs versions de production. Cette nouvelle version de gcc avait un optimiseur de code mort plus agressif. Le compilateur a constaté le comportement indéfini et a décidé que le résultat de la
if
déclaration serait "tout ce qui rend l'optimisation du code optimale", ce qui est une traduction absolument légale de UB. En conséquence, il a supposé que, commeptr+dataLength
il ne pouvait jamais être en-dessousptr
sans débordement de pointeur UB, l’if
instruction ne se déclencherait jamais et qu’elle optimisait la vérification du dépassement de la mémoire tampon.L’utilisation de "sane" UB a en fait causé à un produit SQL majeur un exploit pour lequel il avait écrit du code à éviter!
Ne comptez jamais sur un comportement indéfini. Déjà.
la source
bool
est un excellent exemple de problèmes évidents, mais ils apparaissent ailleurs, à moins que vous ne supposiez que vous travaillez sur une plate-forme très utile comme x86 ou ARM ou MIPS, où tous ces problèmes sont résolus au moment du code d'opération.switch
est inférieur à 8, en raison de la taille de l'arithmétique entière, afin de pouvoir utiliser des instructions rapides supposant qu'il n'y a aucun risque qu'une valeur "grande" entre en entrée. Une valeur non spécifiée (qui ne pourrait jamais être construite à l'aide des règles du compilateur) apparaît, faisant quelque chose d'inattendu, et vous obtenez soudainement un saut énorme à la fin d'une table de saut. Autoriser des résultats non spécifiés ici signifie que chaque instruction switch du programme doit avoir des pièges supplémentaires pour prendre en charge ces cas qui peuvent "ne jamais se produire".Je travaille principalement dans un langage de programmation fonctionnel dans lequel vous n'êtes pas autorisé à réaffecter des variables. Déjà. Cela élimine complètement cette classe de bugs. Cela semblait une énorme restriction au début, mais cela vous oblige à structurer votre code de manière à correspondre à l'ordre d'apprentissage des nouvelles données, ce qui tend à simplifier votre code et à en faciliter la maintenance.
Ces habitudes peuvent également être transposées dans des langues impératives. Il est presque toujours possible de refactoriser votre code pour éviter d'initialiser une variable avec une valeur fictive. C'est ce que ces directives vous disent de faire. Ils veulent que vous y mettiez quelque chose de significatif, pas quelque chose qui rendra simplement les outils automatisés heureux.
Votre exemple avec une API de style C est un peu plus compliqué. Dans ces cas, lorsque j'utilise la fonction, j'initialise à zéro pour empêcher le compilateur de se plaindre, mais une fois dans les
my_read
tests unitaires, je vais initialiser à autre chose pour m'assurer que la condition d'erreur fonctionne correctement. Vous n'avez pas besoin de tester toutes les conditions d'erreur possibles à chaque utilisation.la source
Non, ça ne cache pas les bugs. Au lieu de cela, il rend le comportement déterministe de telle sorte que si un utilisateur rencontre une erreur, un développeur peut la reproduire.
la source
TL; DR: Il existe deux façons de corriger ce programme, d’initialiser vos variables et de prier. Un seul produit des résultats de manière constante.
Avant de pouvoir répondre à votre question, je devrai d'abord expliquer ce que signifie le comportement non défini. En fait, je laisserai un auteur du compilateur faire le gros du travail:
Si vous ne souhaitez pas lire ces articles, un TL; DR est:
L'archétype des "Démons qui volent de votre nez" n'a malheureusement pas réussi à expliquer les conséquences de ce fait. Bien que censé prouver que quelque chose pouvait arriver, il était si incroyable que la plupart du temps, il ait été haussé des épaules.
La vérité, cependant, est que le comportement non défini affecte la compilation elle-même, bien avant que vous n'essayiez d'utiliser le programme (instrumenté ou non, dans un débogueur ou non) et peut changer complètement son comportement.
Je trouve l’exemple de la partie 2 ci-dessus frappant:
est transformé en:
parce qu'il est évident que
P
cela ne peut pas être,0
car il est déréférencé avant d'être vérifié.Comment cela s'applique-t-il à votre exemple?
Eh bien, vous avez commis l’erreur commune de supposer que le comportement non défini entraînerait une erreur d’exécution. Il peut ne pas.
Imaginons que la définition de
my_read
soit:et procéder comme prévu d'un bon compilateur avec inlining:
Ensuite, comme attendu d'un bon compilateur, nous optimisons les branches inutiles:
bytes_read
serait utilisé non initialisé siresult
n'était pas0
result
cela ne le sera jamais0
!Ainsi
result
n'est jamais0
:Oh,
result
n'est jamais utilisé:Oh, nous pouvons reporter la déclaration de
bytes_read
:Et nous en sommes là, une transformation strictement confirmante de l'original, et aucun débogueur ne piégera une variable non initialisée car il n'y en a aucune.
Je suis sur cette voie, comprendre le problème lorsque le comportement attendu et l'assemblage ne correspondent pas n'est vraiment pas amusant.
la source
Regardons de plus près votre exemple de code:
C'est un bon exemple. Si nous anticipons une telle erreur, nous pouvons insérer la ligne
assert(bytes_read > 0);
et intercepter ce bogue au moment de l'exécution, ce qui n'est pas possible avec une variable non initialisée.Mais supposons que non, et nous trouvons une erreur dans la fonction
use(buffer)
. Nous chargeons le programme dans le débogueur, vérifions la trace, et découvrons qu'il a été appelé à partir de ce code. Nous avons donc placé un point d'arrêt en haut de cet extrait de code, réexécutons le processus et reproduisons le bogue. Nous ne faisons qu'un pas en essayant de l'attraper.Si nous n'avons pas initialisé
bytes_read
, il contient des déchets. Il ne contient pas nécessairement la même poubelle à chaque fois. Nous dépassons la lignemy_read(buffer, &bytes_read);
. Maintenant, si la valeur est différente d’avant, nous ne pourrons peut-être pas reproduire notre bogue du tout! Cela pourrait fonctionner la prochaine fois, sur la même entrée, par accident complet. Si c'est toujours zéro, nous obtenons un comportement cohérent.Nous vérifions la valeur, peut-être même sur une trace dans la même exécution. Si c'est zéro, nous pouvons voir que quelque chose ne va pas;
bytes_read
ne devrait pas être zéro sur le succès. (Ou si c'est possible, on pourrait vouloir l'initialiser à -1.) On peut probablement attraper le bogue ici. Si toutefoisbytes_read
une valeur plausible est fausse, la repérerions-nous d'un coup d'œil?Ceci est particulièrement vrai pour les pointeurs: un pointeur NULL sera toujours évident dans un débogueur, il peut être testé très facilement et devrait segfault sur du matériel moderne si nous essayons de le déréférencer. Un pointeur de mémoire peut provoquer ultérieurement des bogues de corruption de la mémoire non reproductibles, ce qui est presque impossible à déboguer.
la source
Le PO ne s'appuie pas sur un comportement indéfini, ou du moins pas exactement. En effet, s’appuyer sur un comportement indéfini est mauvais. Dans le même temps, le comportement d'un programme dans un cas inattendu est également indéfini, mais un type différent d'indéfini. Si vous définissez une variable à zéro, mais vous ne l' avez pas l' intention d'avoir un chemin d'exécution qui utilise ce zéro initial, ce que votre programme se comportent sanely lorsque vous avez un bug et faire un tel chemin? Vous êtes maintenant dans les mauvaises herbes; vous n'aviez pas l'intention d'utiliser cette valeur, mais vous l'utilisez quand même. Peut-être que ce sera inoffensif ou que cela provoquera un crash du programme ou peut-être que le programme corrompra des données en silence. Tu ne sais pas.
Ce que le PO dit, c'est qu'il existe des outils qui vous aideront à trouver ce bogue, si vous le lui permettez. Si vous n'initialisez pas la valeur, mais que vous l'utilisez quand même, il existe des analyseurs statiques et dynamiques qui vous diront que vous avez un bogue. Un analyseur statique vous le dira avant même de commencer à tester le programme. Si, en revanche, vous initialisez aveuglément la valeur, les analyseurs ne peuvent pas dire que vous n'aviez pas prévu d'utiliser cette valeur initiale et votre bogue restera non détecté. Si vous avez de la chance, c'est inoffensif ou simplement le programme est bloqué; si vous êtes malchanceux, les données sont corrompues en silence.
Le seul endroit où je suis en désaccord avec le PO est à la toute fin, où il dit "quand il y aurait déjà une faute de segmentation sinon." En effet, une variable non initialisée ne donnera pas de manière fiable une erreur de segmentation. Au lieu de cela, je dirais que vous devriez utiliser des outils d’analyse statique qui ne vous permettront pas d’essayer d’exécuter le programme.
la source
Une réponse à votre question doit être décomposée en différents types de variables qui apparaissent dans un programme:
Variables locales
Habituellement, la déclaration doit être juste à l’endroit où la variable obtient d’abord sa valeur. Ne pas prédéclarer les variables comme dans l'ancien style C:
Cela supprime 99% du besoin d'initialisation, les variables ont leur valeur finale dès le départ. Les quelques exceptions sont les cas où l'initialisation dépend d'une condition:
Je crois que c'est une bonne idée d'écrire ces cas comme ceci:
C'est à dire. explicitement qu’une initialisation sensible de votre variable est effectuée.
Variables membres
Ici, je suis d’accord avec ce que les autres répondants ont dit: Celles-ci devraient toujours être initialisées par les listes constructeurs / initialiseurs. Sinon, vous avez du mal à assurer la cohérence entre vos membres. Et si vous avez un ensemble de membres qui ne semble pas avoir besoin d'initialisation dans tous les cas, refactorisez votre classe en ajoutant ces membres dans une classe dérivée où ils sont toujours nécessaires.
Les tampons
C'est là où je suis en désaccord avec les autres réponses. Quand les gens deviennent religieux à propos de l'initialisation des variables, ils finissent souvent par initialiser des tampons comme celui-ci:
Je pense que cela est presque toujours préjudiciable: le seul effet de ces initialisations est qu'elles rendent des outils
valgrind
impuissants. Tout code qui lit plus que nécessaire dans les tampons initialisés est très probablement un bogue. Mais avec l'initialisation, ce bug ne peut pas être exposé parvalgrind
. Donc, ne les utilisez pas sauf si vous vous fiez vraiment à la mémoire remplie de zéros (et dans ce cas, laissez un commentaire disant ce pour quoi vous avez besoin des zéros).Je recommande également fortement d'ajouter une cible à votre système de génération qui exécute la suite de tests dans son intégralité
valgrind
ou un outil similaire pour exposer les bogues d'utilisation avant l'initialisation et les fuites de mémoire. Ceci est plus précieux que toutes les préinitialisations de variables. Cettevalgrind
cible doit être exécutée régulièrement, en particulier avant que tout code ne soit rendu public.Variables globales
Vous ne pouvez pas avoir de variables globales non initialisées (du moins en C / C ++, etc.), assurez-vous donc que cette initialisation est celle que vous souhaitez.
la source
Base& b = foo() ? new Derived1 : new Derived2;
Base &b = base_factory(which);
. Ceci est particulièrement utile si vous devez appeler le code plusieurs fois ou s'il vous permet de rendre le résultat constant.?:
un PITA et qu'une fonction d'usine est toujours excessive. Ces cas sont rares, mais ils existent.Un compilateur décent en C, C ++ ou Objective-C avec les bonnes options du compilateur vous dira au moment de la compilation si une variable est utilisée avant que sa valeur ne soit définie. Dans la mesure où, dans ces langages, le comportement indéfini de la valeur d'une variable non initialisée est défini, "définir une valeur avant de l'utiliser" n'est pas un indice, ni une ligne directrice, ni une bonne pratique, il s'agit d'une exigence de 100%; sinon votre programme est absolument en panne. Dans d'autres langages, comme Java et Swift, le compilateur ne vous autorisera jamais à utiliser une variable avant son initialisation.
Il y a une différence logique entre "initialiser" et "définir une valeur". Si je veux trouver le taux de conversion entre dollars et euros, écris "taux double = 0,0;" alors la variable a une valeur définie, mais elle n'est pas initialisée. La 0.0 stockée ici n'a rien à voir avec le résultat correct. Dans cette situation, si à cause d'un bogue, vous ne stockez jamais le taux de conversion correct, le compilateur n'a pas la possibilité de vous le dire. Si vous venez d'écrire "double taux;" et jamais stocké un taux de conversion significatif, le compilateur vous le dirait.
Donc: N'initialisez pas une variable simplement parce que le compilateur vous dit qu'elle est utilisée sans être initialisée. C'est cacher un bug. Le vrai problème est que vous utilisez une variable que vous ne devriez pas utiliser ou que, sur un chemin de code, vous n'avez pas défini de valeur. Corrigez le problème, ne le cachez pas.
N'initialisez pas une variable simplement parce que le compilateur peut vous dire qu'elle est utilisée sans être initialisée. Encore une fois, vous cachez des problèmes.
Déclarez les variables proches de l’utilisation. Cela améliore les chances que vous puissiez l'initialiser avec une valeur significative au moment de la déclaration.
Évitez de réutiliser des variables. Lorsque vous réutilisez une variable, il est fort probable qu'elle soit initialisée à une valeur inutile lorsque vous l'utilisez à des fins différentes.
Il a été signalé que certains compilateurs ont de faux négatifs et que la vérification de l'initialisation équivaut à résoudre le problème. Les deux sont en pratique hors de propos. Si un compilateur, tel que cité, ne peut pas trouver l’utilisation d’une variable non initialisée dix ans après le signalement du bogue, il est temps de chercher un autre compilateur. Java l'implémente deux fois; une fois dans le compilateur, une fois dans le vérificateur, sans aucun problème. Le moyen le plus simple de contourner le problème persistant est de ne pas exiger qu’une variable soit initialisée avant d’être utilisée, mais bien de l’initialiser avant son utilisation de manière à pouvoir être vérifiée par un algorithme simple et rapide.
la source