Namespaces
Variants

Value-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

Ceci est l'initialisation effectuée lorsqu'un objet est construit avec un initialiseur vide.

Table des matières

Syntaxe

T () (1)
new T () (2)
Class :: Class ( ... ) : member () { ... } (3)
T object {}; (4) (depuis C++11)
T {} (5) (depuis C++11)
new T {} (6) (depuis C++11)
Class :: Class ( ... ) : member {} { ... } (7) (depuis C++11)

Explication

L'initialisation par valeur est effectuée dans ces situations :

1,5) lorsqu'un objet temporaire sans nom est créé avec l'initialiseur constitué d'une paire vide de parenthèses ou d'accolades (depuis C++11) ;
2,6) lorsqu'un objet avec une durée de stockage dynamique est créé par une new expression avec l'initialiseur constitué d'une paire vide de parenthèses ou d'accolades (depuis C++11) ;
3,7) lorsqu'un membre de données non statique ou une classe de base est initialisé en utilisant un initialisateur de membre avec une paire de parenthèses vides ou d'accolades (depuis C++11) ;
4) lorsqu'un objet nommé (automatique, statique ou thread-local) est déclaré avec l'initialiseur constitué d'une paire d'accolades.

Dans tous les cas, si la paire d'accolades vide {} est utilisée et que T est un type agrégé, l'initialisation agrégée est effectuée au lieu de l'initialisation par valeur.

Si T est un type de classe qui n'a pas de constructeur par défaut mais possède un constructeur prenant std::initializer_list , l'initialisation par liste est effectuée.

(depuis C++11)

Les effets de l'initialisation par valeur sont :

  • Si T est un type classe (éventuellement qualifié cv) :
  • Sinon, si T est un type tableau, chaque élément du tableau est initialisé par valeur.
  • Sinon, l'objet est initialisé à zéro.

Notes

La syntaxe T object ( ) ; n'initialise pas un objet ; elle déclare une fonction qui ne prend aucun argument et retourne T . La manière de value-initialize une variable nommée avant C++11 était T object = T ( ) ; , ce qui value-initialize un temporaire puis copy-initialize l'objet : la plupart des compilateurs optimisent la copie dans ce cas.

Les références ne peuvent pas être initialisées par valeur.

Comme décrit dans la conversion de type fonction , la syntaxe T ( ) (1) est interdite si T désigne un type tableau, tandis que T { } (5) est autorisée.

Tous les conteneurs standards ( std::vector , std::list , etc.) initialisent par valeur leurs éléments lorsqu'ils sont construits avec un seul argument size_type ou lorsqu'ils sont agrandis par un appel à resize ( ) , sauf si leur allocateur personnalise le comportement de construct .

Exemple

#include <cassert>
#include <iostream>
#include <string>
#include <vector>
struct T1
{
    int mem1;
    std::string mem2;
    virtual void foo() {} // assure que T1 n'est pas un agrégat
}; // constructeur par défaut implicite
struct T2
{
    int mem1;
    std::string mem2;
    T2(const T2&) {} // constructeur de copie fourni par l'utilisateur
};                   // pas de constructeur par défaut
struct T3
{
    int mem1;
    std::string mem2;
    T3() {} // constructeur par défaut fourni par l'utilisateur
};
std::string s{}; // classe => initialisation par défaut, la valeur est ""
int main()
{
    int n{};                // scalaire => initialisation à zéro, la valeur est 0
    assert(n == 0);
    double f = double();    // scalaire => initialisation à zéro, la valeur est 0.0
    assert(f == 0.0);
    int* a = new int[10](); // tableau => initialisation par valeur de chaque élément
    assert(a[9] == 0);      //          la valeur de chaque élément est 0
    T1 t1{};                // classe avec constructeur par défaut implicite =>
    assert(t1.mem1 == 0);   //     t1.mem1 est initialisé à zéro, la valeur est 0
    assert(t1.mem2 == "");  //     t1.mem2 est initialisé par défaut, la valeur est ""
//  T2 t2{};                // erreur : classe sans constructeur par défaut
    T3 t3{};                // classe avec constructeur par défaut fourni par l'utilisateur =>
    std::cout << t3.mem1;   //     t3.mem1 est initialisé par défaut à une valeur indéterminée
    assert(t3.mem2 == "");  //     t3.mem2 est initialisé par défaut, la valeur est ""
    std::vector<int> v(3);  // initialisation par valeur de chaque élément
    assert(v[2] == 0);      // la valeur de chaque élément est 0
    std::cout << '\n';
    delete[] a;
}

Sortie possible :

42

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 publié Comportement corrigé
CWG 178 C++98 il n'y avait pas d'initialisation par valeur ; un initialiseur vide invoquait l'initialisation
par défaut (bien que new T ( ) effectue également une initialisation à zéro)
l'initialiseur vide invoque
l'initialisation par valeur
CWG 543 C++98 l'initialisation par valeur pour un objet de classe sans aucun
constructeur fourni par l'utilisateur était équivalente à l'initialisation
par valeur de chaque sous-objet (ce qui ne nécessitait pas d'initialiser à zéro
un membre avec un constructeur par défaut fourni par l'utilisateur)
initialise à zéro
l'objet entier,
puis appelle le
constructeur par défaut
CWG 1301 C++11 l'initialisation par valeur des unions avec des constructeurs
par défaut supprimés conduisait à une initialisation à zéro
elles sont
initialisées par défaut
CWG 1368 C++98 tout constructeur fourni par l'utilisateur entraînait
l'omission de l'initialisation à zéro
seul un constructeur par défaut
fourni par l'utilisateur
omet l'initialisation à zéro
CWG 1502 C++11 l'initialisation par valeur d'une union sans constructeur par défaut
fourni par l'utilisateur n'initialisait que l'objet à zéro,
malgré les initialiseurs de membres par défaut
effectue l'initialisation
par défaut après
l'initialisation à zéro
CWG 1507 C++98 l'initialisation par valeur pour un objet de classe sans aucun
constructeur fourni par l'utilisateur ne vérifiait pas la validité
du constructeur par défaut lorsque ce dernier est trivial
la validité du constructeur
par défaut trivial
est vérifiée
CWG 2820 C++98 l'initialisation par défaut suivant l'initialisation à zéro
nécessitait un constructeur non trivial
non requis
CWG 2859 C++98 l'initialisation par valeur pour un objet de classe pouvait impliquer
une initialisation à zéro même si l'initialisation par défaut
ne sélectionnait pas réellement un constructeur fourni par l'utilisateur
il n'y a pas
d'initialisation à zéro
dans ce cas

Voir aussi