ProgrammationDéveloppeur C++

Comment fonctionne le mécanisme de liste d'initialisation (initializer list) en C++ ? Dans quels cas l'utilisation de la liste d'initialisation est-elle critiques pour l'exactitude et les performances ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question

Dans les premières versions de C++, les membres de classe étaient initialisés à l'intérieur du constructeur par affectation. Par la suite, il est devenu possible d'initialiser les membres de classe avant d'entrer dans le corps du constructeur à l'aide d'une liste d'initialisation, ce qui est crucial pour les membres constants, les références et les performances.

Problème

Certains membres de classe (comme les champs const ou les références) ne peuvent pas être initialisés par l'affectation à l'intérieur du corps du constructeur — ils doivent être définis au moment de la création. De plus, si vous utilisez l'affectation, le constructeur par défaut sera appelé en premier, puis l'affectation (deux actions), ce qui peut être coûteux pour des objets complexes:

class Example { const int x; std::string str; public: Example(int val, const std::string& s) : x(val), str(s) {} };

Solution

Utilisez la liste d'initialisation pour initialiser immédiatement les membres de la classe. C'est particulièrement important pour les const, les références, les classes membres sans constructeur par défaut, ainsi que pour les performances lors du travail avec des classes STL et de grandes structures.

Exemple de code:

class Point { const int x; int& y; public: Point(int val, int& ref) : x(val), y(ref) {} };

Caractéristiques clés :

  • Nécessaire pour les membres const et les références
  • Optimise les performances (sans appel au constructeur par défaut)
  • Donne un contrôle total sur l'ordre d'initialisation

Questions pièges.

Peut-on changer l'ordre d'initialisation des membres de la classe par l'ordre dans la liste d'initialisation du constructeur ?

Non ! Les membres sont toujours initialisés dans l'ordre de leur déclaration dans la classe, et non dans l'ordre de la liste d'initialisation. Ignorer cette règle conduit à des erreurs d'ordre d'initialisation.


Que se passe-t-il si un membre-référence n’est pas initialisé dans la liste d'initialisation, mais seulement dans le corps du constructeur ?

Erreur de compilation ! Une référence, tout comme les champs const, ne peut être initialisée que dans la liste d'initialisation — elle doit recevoir une valeur avant d'entrer dans le corps du constructeur.


Après l'initialisation d'un membre const dans la liste d'initialisation, peut-on le modifier dans le corps du constructeur ?

Non, un membre constant ne peut pas être modifié après l'initialisation — essayer de modifier un tel champ entraînera une erreur de compilation.

Erreurs typiques et anti-modèles

  • Affectation au lieu d'initialisation pour les champs const/à affectation unique
  • Non-correspondance entre l'ordre de déclaration des membres et l'ordre dans la liste d'initialisation
  • Initialisation de champs dépendants sans tenir compte de l'ordre

Exemple de la vie réelle

Cas négatif

Dans le constructeur, le membre de la classe est initialisé à l'intérieur du corps du constructeur. Pour des objets complexes, des ressources sont dépensées pour appeler le constructeur par défaut, puis pour l'affectation, puis pour la destruction de l'objet temporaire.

Avantages :

  • Visuellement plus simple pour les débutants

Inconvénients :

  • Ne fonctionne pas pour les const et les références
  • Surcharge de performance
  • Erreurs d'ordre d'initialisation

Cas positif

Tous les membres sont immédiatement initialisés dans la liste d'initialisation, sans opérations supplémentaires ni problèmes avec les champs immuables.

Avantages :

  • Exactitude pour les const et les références
  • Haute performance

Inconvénients :

  • Nécessite une attention particulière à l'ordre de déclaration des membres