Pourquoi initialiser les variable membre d'une class/struct

Merci pour vos explications.

Le problème exposé dans ce sujet a été résolu.

Encore moi,

Certains d’entre nous ne sont pas des messieurs :(

ache

Oups! Avec mes excuses, c’était pas fait exprès (Les habitudes du boulot !) Et c’est vrai qu’avec les speudos on peut se gourer.

Parce qu’il y a le problème de "on ne paie pas pour ce qu’on n’a pas besoin" en C++.

Bof, ça coutera pas grand-chose ! (ref à la perte de performance)

Plus le problème de savoir quoi initialiser. Initialiser à 0 peut éviter les UB, mais cela peut provoquer aussi un "bug" (un comportement pas souhaité) qui sera difficile à détecter.

Pour moi le point le plus difficile, c’est le UB. Quand c’est reproductible, c’est plus facile à débuger. (Ref programmation par contrat : les préconditions)

De toute façon, si tu es dans un domaine critique, il faut utiliser un max d’outils de détection.

Oh la la: la qualification des outils … Vaste sujet … (Mais on ne programme pas en C++ le soft critique !)

On pourrait imaginer une option dans les compilos pour forcer l’initialisation par défaut. Mais je n’ai jamais vu ce genre d’option (ou je ne m’en souviens pas).

… Par-contre ça m’étonne que les compilateurs C++ n’aient pas ce genre d’options.

Donc je ne suis pas le seul à me poser la question.

Aprés, rien n’empêche d’écrire ton propre type qui s’auto initialiserait. C’est que font les smart ptr comparé aux raw ptr, ou vector/array comparés aux C-array.

Merci pour l’exemple.

Cordialement

Parce qu’il y a le problème de "on ne paie pas pour ce qu’on n’a pas besoin" en C++.

Bof, ça coutera pas grand-chose ! (ref à la perte de performance)

Dedeun

Ce n’est pas une question de performance mais d’idéologie. Le compilateur fait ce que tu dis. Dans l’idéal. Il devrait y avoir un syntaxe claire pour dire « Je ne veux pas que ça soit initialisé ». Et cette syntaxe ne devrait être qu’explicite; càd ne pas se confondre avec j’ai oublié d’initialiser.

Or là, elle est implicite, ce qu’on n’aime pas en C++.

+0 -0

On pourrait imaginer une option dans les compilos pour forcer l’initialisation par défaut. Mais je n’ai jamais vu ce genre d’option (ou je ne m’en souviens pas).

Clang possède -ftrivial-auto-var-init=pattern qui met tous les octets non initialisés à 0xAA/0b10101010, mais pas moyen de définir une valeur random à chaque build :'(

Si j’ai bien compris un bug récent, sous AIX, les pointeurs non initialisés valent quelque chose comme 0x1, tandis que ceux initialisés nuls valent 0x0. Tout mettre à 0x0 par défaut casserai la compatibilité, car un if (pointer) capturerai les pointeurs non initialisés.

Gabbro

Le bug est plutôt de se reposer sur un comportement UB d’après la norme. Se reposer sur un tel comportement rend également le code non-portable puisqu’il change selon les plateformes et compilateurs. D’ailleurs, je doute qu’on puisse faire grand-chose avec un pointeur à 0x01.

Ce n’est pas une question de performance mais d’idéologie. Le compilateur fait ce que tu dis. Dans l’idéal. Il devrait y avoir une syntaxe claire pour dire « Je ne veux pas que ça soit initialisé ». Et cette syntaxe ne devrait être explicite

Il y a des propositions pour ça (je n’ai plus le papier en tête). Le but étant aussi de pouvoir différer l’initialisation tout en déclarant la variable pour être stockée (ni lu, ni écrite, juste référencée) et de traquer plus facilement les chemins des valeurs non-initialisée et/ou à initialiser (notion de paramètre in/out).

Le problème est que c’est un comportement totalement inverse de ce qui se fait actuellement et rend compliqué sa mise en pratique.

Quant à vouloir initialiser par défaut, c’est, jusqu’où ? Si je fais un buffer, il faudrait tout mettre à 0 ? C’est inutile si mon but est d’écrire dedans plus tard. Mettre tout à 0 avec l’allocation dynamique ? Quel intérêt avec std::vector::reserve() ?

On tombe sur des cas où cette initialisation a un coût pas forcément négligeable, mais surtout inutile (on a bien un problème de performance). On tombe aussi sur ceux cités par @lmghs concernant les outils d’analyses qui ne peuvent plus détecter des valeurs non initialisées (normal, elles n’existent plus).

Trop de messages et d’auteurs (corrigez-moi s’il y eu une autrice, aux accords je n’ai pas souvenir), c’est parti pour des réponses à des citations anonymes ^^' (et je vois que jo a été plus rapide que moi)

Réflexion faite, je me pose la question : étant donné les puissances des processeurs (L’argument du gain de performance me semble plus très convaincant), pourquoi le compilateur n’initialise pas par défaut les valeurs des variables, à la déclaration ?

Cela pourrait changer des comportements. J’ai croisé des programmes qui reposaient, à tord (car UB => le compilo fait ce qu’il veut), sur une pseudo initialisation aléatoire de variables non initialisées. Mais le pire pour moi, c’est que cela va cacher des erreurs.

A noter que MSVC initialiser les variables avec des valeurs spécifiques, en débug, justement pour faciliter la détection.

Et c’est à mon avis une très mauvaise idée. Un programme en débug devrait planter plus facilement qu’en release, car c’est dans les phases de tests qui tournent en debug que l’on chasse les bugs, comme le nom l’indique: dé-bug. Résultat des codes tombent en marche en débug, mais plantent en release, et des produits sont releasées au client en débug car ils plantent-c’est-pas-ma-faute en release…

On pourrait imaginer une option dans les compilos pour forcer l’initialisation par défaut. Mais je n’ai jamais vu ce genre d’option (ou je ne m’en souviens pas).

Ca existe bien chez certains compilos. Je croyais que c’était gcc, ça serait donc clang.

Je pense effectivement que le C se veut le plus proche de ce que le programmeur écrit.

Ah ah ah ah. S’ils savaient :D (hint: règle du as-if => le compilo a pour seule obligation de générer un code qui produit un résultat observable conforme à un code défini — i.e. sans UB)

Pour moi le point le plus difficile, c’est le UB. Quand c’est reproductible, c’est plus facile à débuger.

Quand une erreur numérique produit toujours le même résultat incorrect, ce peut aussi être plus difficile à repérer, surtout quand on n’a pas de référence/baseline pour tester le résultat. Je trouve ça plus fourbe. Maintenant je parle bien du cas numérique. Pour les pointeurs, je vis dans un monde de RAII: j’ai des invariants.

Ce n’est pas une question de performance mais d’idéologie. Le compilateur fait ce que tu dis. Dans l’idéal. Il devrait y avoir un syntaxe claire pour dire « Je ne veux pas que ça soit initialisé ». Et cette syntaxe ne devrait être qu’explicite; càd ne pas se confondre avec j’ai oublié d’initialiser.

Il me semble avoir vu des papiers en ce sens. C’est un débat récurrent sur r/cpp (reddit) Le problème est que cela va impacter rétroactivement trop de codes. Une seule solution: interdire à la place la déclaration de variables numériques sans initialisation. Obligation de const ou de AAA. Là, on est sûr qu’on n’aura plus de numériques dans des états quantiques. Cela corrigera toutes les problématiques: non-initialisé, pessimisation, ou initialisé à des valeurs bidons (pour ce dernier seul const apporte une solution absolue vu que l’on peut faire du AAA avec init à 0xbadc0de et espérer réaffecter après…)

Merci pour ces nouvelles réponses, Mesdames/Messieurs,

Je ne suis pas forcément d’accord avec tout, mais je pense que vous en savez plus que moi, alors je ne relance pas. Je constate que s’il y a "des papiers dans ce sens", c’est que mes questions existentielles sur l’initialisation des variables, c’est pas si con !

Je me permets juste une dernière demande (la "der des der", comme ils disaient), j’ai compris que AAA, c’est "Almost Always Auto". LMGHS, quel est le lien avec l’initialisation des variables ? (const, oui, c’est évidant).

… Une seule solution: interdire à la place la déclaration de variables numériques sans initialisation. Obligation de const ou de AAA. Là, on est sûr qu’on n’aura plus de numériques dans des états quantiques. Cela corrigera toutes les problématiques: non-initialisé, pessimisation, ou initialisé à des valeurs bidons (pour ce dernier seul const apporte une solution absolue vu que l’on peut faire du AAA avec init à 0xbadc0de et espérer réaffecter après…)

lmghs

Merci de bien vouloir m’expliquer.

Cordialement

PS : Est-ce que ça veut dire que, étant donné que si on déclare une variable de type auto, son type réel est défini par la valeur d’initialisation, donc en maximisant/obligant l’utilisation des déclarations de type auto, les variables seraient initialisées ?

+0 -0

Je constate que s’il y a "des papiers dans ce sens", c’est que mes questions existentielles sur l’initialisation des variables, c’est pas si con !

Ou que tout le monde n’est pas d’accord sur le sujet de la programmation défensive. C’est comme "operator[] devrait faire de la vérification de bornes comme en Java". Est-ce que cela va vraiment nous sauver de nos erreurs? Pour ceux qui ont lu le papier d’Herb Sutter sur les exception déterministes, je lis entre les lignes que nous partageons un avis similaire sur at(): cela n’aurait jamais du exister. Il cite l’article de Joe Duffy relatif à la conception de son langage pour faire en particulier référence au chapitre: "Bugs aren’t recoverable errors"

Je me permets juste une dernière demande (la "der des der", comme ils disaient), j’ai compris que AAA, c’est "Almost Always Auto". LMGHS, quel est le lien avec l’initialisation des variables ? (const, oui, c’est évidant).

On en revient à ce bout de FAQ que j’avais écrit en réaction à une règle normative dans le référentiel d’un client ("toujours déclarer une variable en début de bloc"): "Où dois-je déclarer mes variables locales?", et que j’ai développé dans une conf (slides)

Résumé rapide. Le problème, c’est Point2d p;. Faut-il laisser p dans un état sale, ou faut-il le forcer à une valeur neutre et si oui laquelle? Avec auto p = Point2d{???};, il n’y a plus le choix, le point devra être initialisé.

Il y a plein de questions autour de cela: faut-il forcer à 0 (ou autre) à cause du poids des passifs Pascal et C89 où l’on devait obligatoirement déclarer nos variables en début de bloc. Passifs qui se ressentent dans les réflexes de nos camarades de projets qui aimeront continuer à écrire Type v; + v = 42;. Quand c’est une ligne après l’autre, c’est maladroit. Quand il y a 15 lignes entre les deux, c’est dangereux.

Avec auto il n’est plus possible de faire cela. Cela pousse à retarder les déclarations, et en plus ce ne permet pas de laisser dans un état indéterminé. Si on rajoute const, c’est encore mieux, on est sûr d’interdire les états transitoires bidons parce que FUD ou parce que des règles qualité (FUDiennes) demandent à ce que toute variable soit déclarée et initialisée en début de bloc, même s’il faudra changer l’état 4 pages d’écran plus loin — ouais trop souvent les fonctions longues sont plus facilement tolérées que les variables non initialisées.

Le problème est si l’état transitoire (qu’il soit bidon par choix, ou indéterminé) arrive jusqu’au point où la variable est consommée pour en faire quelque chose. <parenthèse>(Le monde idéal: on ne déclare jamais de variables que l’on ne soit pas capable de mettre de suite dans son état pertinent final. auto réduit donc les vieilles habitudes qui conduisent à cet état transitoire inutile. const l’élimine.)</>

Le débat est: choix bidon ou indéterminé darwiniste? Le choix bidon a l’avantage que souvent on voulait 0 et le/la dev a été trop feignasse pour rajouter le = 0. Le darwinisme a une chance (malheureusement pas de 100%) d’être détecté par warning-de-compilo/analyse-statique/sanitizer/valgrind. Le choix bidon ne peut être détecté qu’avec des baselines correctes.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte