Namespaces
Variants

Initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Initialisation d'une variable fournit sa valeur initiale au moment de la construction.

La valeur initiale peut être fournie dans la section d'initialisation d'un déclarateur ou d'une expression new . Elle intervient également lors des appels de fonction : les paramètres de fonction et les valeurs de retour de fonction sont également initialisés.

Table des matières

Initialiseurs

Pour chaque déclarateur, l' initializer (s'il existe) peut être l'un des suivants :

= expression (1)
= {}
= { initializer-list }
= { designated-initializer-list }
(2)

(depuis C++20)
( expression-list )
( initializer-list )
(3) (jusqu'à C++11)
(depuis C++11)
{}
{ initializer-list }
{ designated-initializer-list }
(4) (depuis C++11)
(depuis C++11)
(depuis C++20)
1) Syntaxe de copie-initialisation.
2) Syntaxe d'initialisation agrégée. (jusqu'à C++11) Syntaxe d'initialisation par liste. (depuis C++11)
3) Syntaxe de l'initialisation directe.
4) Syntaxe de l'initialisation de liste.
expression - toute expression (sauf les expressions virgule non parenthésées)
expression-list - une liste d'expressions séparées par des virgules (sauf les expressions virgule non parenthésées)
initializer-list - une liste de clauses d'initialisation séparées par des virgules (voir ci-dessous)
designated-initializer-list - une liste de clauses d'initialisation désignées séparées par des virgules


Une clause d'initialisation peut être l'une des suivantes :

expression (1)
{} (2)
{ liste-d'initialisation } (3)
{ liste-d'initialisateurs-désignés } (4) (depuis C++20)

Syntaxes (2-4) sont collectivement appelées brace-enclosed initializer list .

Sémantique des initialiseurs

Si aucun initialiseur n'est spécifié pour un objet, l'objet est default-initialized . Si aucun initialiseur n'est spécifié pour une reference , le programme est mal formé.

Si l'initialiseur spécifié pour un objet est ( ) (ne peut pas apparaître dans les déclarateurs en raison de la restriction syntaxique), l'objet est value-initialized . Si l'initialiseur spécifié pour une référence est ( ) , le programme est mal formé.

La sémantique des initialiseurs est la suivante :

  • Si l'entité initialisée est une référence, voir reference initialization .
  • Sinon, l'entité initialisée est un objet. Étant donné le type de l'objet comme T :
  • Si l'initialiseur est de syntaxe (2) :
(jusqu'à C++11)
(depuis C++11)
#include <string>
std::string s1;           // initialisation par défaut
std::string s2();         // PAS une initialisation !
                          // déclare en fait une fonction « s2 »
                          // sans paramètre et retournant std::string
std::string s3 = "hello"; // initialisation par copie
std::string s4("hello");  // initialisation directe
std::string s5{'a'};      // initialisation par liste (depuis C++11)
char a[3] = {'a', 'b'}; // initialisation d'agrégat
                        // (partie de l'initialisation par liste depuis C++11)
char& c = a[0];         // initialisation de référence

Variables non locales

Toutes les variables non locales avec une durée de stockage statique sont initialisées lors du démarrage du programme, avant l'exécution de la fonction main (sauf report, voir ci-dessous). Toutes les variables non locales avec une durée de stockage locale au thread sont initialisées lors du lancement du thread, séquencées avant le début de l'exécution de la fonction du thread. Pour ces deux classes de variables, l'initialisation se produit en deux étapes distinctes :

Initialisation statique

Il existe deux formes d'initialisation statique :

1) Si possible, l'initialisation constante est appliquée.
2) Sinon, les variables statiques non locales et les variables locales de thread sont zero-initialized .

En pratique :

  • L'initialisation constante est généralement appliquée au moment de la compilation. Les représentations d'objets pré-calculées sont stockées dans le cadre de l'image du programme. Si le compilateur ne fait pas cela, il doit quand même garantir que l'initialisation se produit avant toute initialisation dynamique.
  • Les variables à initialiser à zéro sont placées dans le segment .bss de l'image du programme, qui n'occupe aucun espace sur le disque et est mis à zéro par le système d'exploitation lors du chargement du programme.

Initialisation dynamique

Une fois que toutes les initialisations statiques sont terminées, l'initialisation dynamique des variables non locales se produit dans les situations suivantes :

1) Initialisation dynamique non ordonnée , qui s'applique uniquement aux membres de données statiques de modèles de classe (statiques/locaux au thread) et aux modèles de variables (depuis C++14) qui ne sont pas explicitement spécialisés . L'initialisation de ces variables statiques est séquencée de manière indéterminée par rapport à toute autre initialisation dynamique sauf si le programme démarre un thread avant l'initialisation d'une variable, auquel cas son initialisation est non séquencée (depuis C++17) . L'initialisation de ces variables locales au thread est non séquencée par rapport à toute autre initialisation dynamique.
2) Initialisation dynamique partiellement ordonnée , qui s'applique à toutes les variables inline qui ne sont pas une spécialisation implicitement ou explicitement instanciée. Si un V partiellement ordonné est défini avant un W ordonné ou partiellement ordonné dans chaque unité de traduction, l'initialisation de V est séquencée avant l'initialisation de W (ou se produit-avant, si le programme démarre un thread).
(depuis C++17)
3) Initialisation dynamique ordonnée , qui s'applique à toutes les autres variables non locales : au sein d'une seule unité de traduction, l'initialisation de ces variables est toujours séquencée dans l'ordre exact où leurs définitions apparaissent dans le code source. L'initialisation des variables statiques dans différentes unités de traduction est séquencée de manière indéterminée. L'initialisation des variables locales de thread dans différentes unités de traduction n'est pas séquencée.

Si l'initialisation d'une variable non locale avec une durée de stockage statique ou thread se termine via une exception, std::terminate est appelée.

Initialisation dynamique précoce

Les compilateurs sont autorisés à initialiser les variables à initialisation dynamique dans le cadre de l'initialisation statique (essentiellement, au moment de la compilation), si les deux conditions suivantes sont remplies :

1) la version dynamique de l'initialisation ne modifie pas la valeur d'un autre objet de portée d'espace de noms avant son initialisation
2) la version statique de l'initialisation produit la même valeur dans la variable initialisée que celle qui serait produite par l'initialisation dynamique si toutes les variables non requises pour être initialisées statiquement étaient initialisées dynamiquement.

En raison de la règle ci-dessus, si l'initialisation d'un objet o1 fait référence à un objet de portée de namespace o2 , qui nécessite potentiellement une initialisation dynamique, mais est défini ultérieurement dans la même unité de traduction, il n'est pas spécifié si la valeur de o2 utilisée sera la valeur de o2 entièrement initialisé (car le compilateur a promu l'initialisation de o2 au moment de la compilation) ou sera la valeur de o2 simplement initialisé à zéro.

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;   // non spécifié :
                  // initialisé dynamiquement à 0.0 si d1 est initialisé dynamiquement, ou
                  // initialisé dynamiquement à 1.0 si d1 est initialisé statiquement, ou
                  // initialisé statiquement à 0.0 (car ce serait sa valeur
                  // si les deux variables étaient initialisées dynamiquement)
double d1 = fd(); // peut être initialisé statiquement ou dynamiquement à 1.0

Initialisation dynamique différée

Il est défini par l'implémentation si l'initialisation dynamique se produit avant la première instruction de la fonction main (pour les statiques) ou la fonction initiale du thread (pour les thread-locals), ou si elle est différée pour se produire après.

Si l'initialisation d'une variable non inline (depuis C++17) est différée pour se produire après la première instruction de la fonction main/thread, elle se produit avant la première ODR-use de toute variable avec une durée de stockage statique/thread définie dans la même unité de traduction que la variable à initialiser. Si aucune variable ou fonction n'est ODR-usée depuis une unité de traduction donnée, les variables non locales définies dans cette unité de traduction peuvent ne jamais être initialisées (cela modélise le comportement d'une bibliothèque dynamique à la demande). Cependant, tant que quelque chose d'une unité de traduction est ODR-usé, toutes les variables non locales dont l'initialisation ou la destruction a des effets secondaires seront initialisées même si elles ne sont pas utilisées dans le programme.

Si l'initialisation d'une variable inline est différée, elle se produit avant la première ODR-use de cette variable spécifique.

(since C++17)
// ============
// == Fichier 1 ==
#include "a.h"
#include "b.h"
B b;
A::A() { b.Use(); }
// ============
// == Fichier 2 ==
#include "a.h"
A a;
// ============
// == Fichier 3 ==
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main()
{
    a.Use();
    b.Use();
}
// Si a est initialisé avant l'entrée dans main, b peut encore être non initialisé
// au moment où A::A() l'utilise (car l'initialisation dynamique est
// séquencée de manière indéterminée entre les unités de traduction)
// Si a est initialisé à un moment après la première instruction de main (qui utilise odr
// une fonction définie dans le Fichier 1, forçant son initialisation dynamique à s'exécuter),
// alors b sera initialisé avant son utilisation dans A::A

Variables locales statiques

Pour l'initialisation des variables statiques locales (c'est-à-dire de portée de bloc) et des variables thread-local, voir static block variables .

L'initialiseur n'est pas autorisé dans une déclaration de variable à portée de bloc avec liaison externe ou interne . Une telle déclaration doit apparaître avec extern et ne peut pas être une définition.

Membres de classe

Les membres de données non statiques peuvent être initialisés avec une liste d'initialisation de membre ou avec un initialiseur de membre par défaut .

Notes

L'ordre de destruction des variables non locales est décrit dans std::exit .

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 270 C++98 l'ordre d'initialisation des membres de données statiques
des modèles de classe n'était pas spécifié
spécifié comme non ordonné sauf pour
les spécialisations et définitions explicites
CWG 441 C++98 les références non locales avec durée de stockage statique n'étaient
pas toujours initialisées avant les initialisations dynamiques
considérées comme une initialisation statique, toujours
initialisées avant les initialisations dynamiques
CWG 1415 C++98 une déclaration de variable extern de portée de bloc
pouvait être une définition
interdite (aucun initialiseur
autorisé dans de telles déclarations)
CWG 2599 C++98 il n'était pas clair si l'évaluation des arguments de fonction
dans l'initialiseur fait partie de l'initialisation
cela fait partie de l'initialisation

Voir aussi

Documentation C pour Initialization