Pourquoi devrais-je initialiser les variables membres dans l’ordre dans lequel elles sont déclarées?

J’écrivais du code aujourd’hui et j’ai eu une erreur de compilation étrange, qui semble être due à l’initialisation des variables membres dans un ordre différent de celui qu’ils ont été déclarés.

Exemple:

class Test { int a; int b; public: Test() : b(1), a(2) { } }; int main() { Test test; return 0; } 

Alors si je le comstack avec -Werror -Wall :

 $ g++ -Werror -Wall test.cpp test.cpp: In constructor 'Test::Test()': test.cpp:3:9: error: 'Test::b' will be initialized after [-Werror=reorder] test.cpp:2:9: error: 'int Test::a' [-Werror=reorder] test.cpp:6:5: error: when initialized here [-Werror=reorder] cc1plus: all warnings being treated as errors 

Je me rends compte que -Wall demande explicitement à GCC d’aller au-dessus des avertissements, mais je suppose qu’il y a une raison pour tous. Alors, comment l’ordre d’initialisation des variables membres pourrait-il être important?

La raison en est parce qu’ils sont initialisés dans l’ordre dans lequel ils ont été déclarés dans votre classe, et non dans l’ordre dans lequel vous les initialisez dans le constructeur et cela vous avertit que l’ordre de votre constructeur ne sera pas utilisé.

Cela permet d’éviter les erreurs lorsque l’initialisation de b dépend d’ a ou vice versa.

La raison de cet ordre est qu’il n’ya qu’un seul destructeur et qu’il doit choisir un «ordre inverse» pour détruire le membre de la classe. Dans ce cas, la solution la plus simple consistait à utiliser l’ordre de déclaration dans la classe pour s’assurer que les atsortingbuts étaient toujours détruits dans l’ordre inverse.

Pourquoi devrais-je initialiser les variables membres dans l’ordre dans lequel elles sont déclarées?

Les membres seront initialisés dans l’ordre dans lequel ils ont été déclarés, que vous le vouliez ou non. L’avertissement vous indique que l’ordre que vous demandez diffère de l’ordre d’exécution réel de l’initialisation.

Vous ne devriez pas, car cela diminue la lisibilité et est potentiellement trompeur.

Si vous avez fait:

 Test() : b(1), a(b) {} 

il semblerait que b alors a étaient tous deux mis à 1 , alors qu’en réalité la valeur non initialisée de b est utilisée pour initialiser a avant que b soit initialisé à 1 .

En fait, le compilateur initialise toujours les variables dans l’ordre de déclaration, même si vous écrivez les initialiseurs dans un ordre différent. Par conséquent, si vous n’écrivez pas les initialisations dans l’ordre de déclaration, l’ordre de vos initialiseurs ne correspond pas à l’ordre d’initialisation, ce qui peut conduire à des bogues subtils si les initialisations dépendent les unes des autres.

Par exemple, considérons le code

 Test(): b(42), a(b) {} 

Ceci est un bogue car a est initialisé avant b , mais cela semble correct. Si vous l’écrivez dans l’ordre de déclaration (qui est l’ordre d’initialisation), le bogue devient évident:

 Test(): a(b), b(42) {} 

Notez que le bogue peut aussi être plus subtil que cela; Par exemple, imaginez a et b sont des types de classes qui produisent quelque chose dans leur constructeur; alors, avec l’ordre “incorrect”, vous penseriez que la sortie de b devrait apparaître avant a ‘alors qu’en réalité l’inverse se produira. Si la sortie apparaissant en premier entraîne un fichier invalide, c’est aussi un bogue, mais le compilateur ne peut pas remarquer le problème si les constructeurs sont dans une autre unité de traduction (à part le fait que le compilateur ne peut pas savoir si le réordonnancement est ou n’est pas un bug). Par conséquent, il est raisonnable que le compilateur avertisse à propos de chaque instance d’ordre non correspondant.

Je me rends compte que -Wall demande explicitement à GCC d’aller au-dessus des avertissements, mais je suppose qu’il y a une raison pour tous.

-Wall n’est qu’un début. Contrairement à ce que son nom implique, -Wall n’autorise pas tous les avertissements. Certains avertissements sont sans doute “excessifs”, mais ce sont précisément les avertissements que -Wall ne permet pas. J’utilise toujours -Wall plus d’autres.

En ce qui concerne votre plainte, comme d’autres l’ont déjà fait remarquer, il existe une très bonne raison pour cet avertissement. Ce n’est pas parce que vous spécifiez une commande que le compilateur utilisera cet ordre. L’ordre que le compilateur doit utiliser selon la norme est basé sur la définition de la classe.