Que signifient les phrases suivantes en C++:
initialisation zéro,
initialisation par défaut, et
initialisation de la valeur
Que doit savoir un développeur C++ à leur sujet?
Une chose à réaliser est que "l'initialisation de la valeur" est nouvelle avec la norme C++ 2003 - elle n'existe pas dans la norme originale de 1998 (je pense que c'est peut-être la seule différence qui est plus qu'une clarification). Voir réponse de Kirill V. Lyadvinsky pour les définitions directement issues de la norme.
Voir cette réponse précédente sur le comportement de operator new
pour plus de détails sur les différents comportements de ces types d'initialisation et quand ils démarrent (et quand ils diffèrent de c ++ 98 à C++ 03):
Le point principal de la réponse est:
Parfois, la mémoire renvoyée par le nouvel opérateur sera initialisée, et parfois cela ne dépendra pas si le type que vous créez est un POD, ou s'il s'agit d'une classe qui contient des membres du POD et utilise un constructeur par défaut généré par le compilateur .
- En C++ 1998, il existe 2 types d'initialisation: zéro et par défaut
- En C++ 2003 un 3ème type d'initialisation, l'initialisation de valeur a été ajoutée.
Pour dire le moins, c'est assez complexe et quand les différentes méthodes interviennent sont subtiles.
Une chose à savoir est que MSVC suit les règles C++ 98, même dans VS 2008 (VC 9 ou cl.exe version 15.x).
L'extrait suivant montre que MSVC et Digital Mars suivent les règles C++ 98, tandis que GCC 3.4.5 et Comeau suivent les règles C++ 03:
#include <cstdio>
#include <cstring>
#include <new>
struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m
int main()
{
char buf[sizeof(B)];
std::memset( buf, 0x5a, sizeof( buf));
// use placement new on the memset'ed buffer to make sure
// if we see a zero result it's due to an explicit
// value initialization
B* pB = new(buf) B(); //C++98 rules - pB->m is uninitialized
//C++03 rules - pB->m is set to 0
std::printf( "m is %d\n", pB->m);
return 0;
}
C++ 03 Standard 8.5/5:
Pour initialiser zéro un objet de type T signifie:
- si T est un type scalaire (3.9), l'objet est mis à la valeur de 0 (zéro) convertie en T;
- si T est un type de classe non-union, chaque membre de données non statique et chaque sous-objet de classe de base sont initialisés à zéro;
- si T est un type d'union, le premier membre de données nommé de l'objet est initialisé à zéro;
- si T est un type de tableau, chaque élément est initialisé à zéro;
- si T est un type de référence, aucune initialisation n'est effectuée.Pour initialiser par défaut un objet de type T signifie:
- si T est un type de classe non POD (article 9), le constructeur par défaut pour T est appelé (et l'initialisation est incorrecte si T n'a pas de constructeur par défaut accessible);
- si T est un type de tableau, chaque élément est initialisé par défaut;
- sinon, l'objet est initialisé à zéro.To value-initialize un objet de type T signifie:
- si T est un type de classe (article 9) avec un constructeur déclaré par l'utilisateur (12.1), alors le constructeur par défaut pour T est appelé (et l'initialisation est incorrecte si T n'a pas de constructeur par défaut accessible) ;
- si T est un type de classe non-union sans constructeur déclaré par l'utilisateur, alors chaque membre de données non statique et composant de classe de base de T est initialisé en valeur;
- si T est un type de tableau, alors chaque élément est initialisé en valeur;
- sinon, l'objet est initialisé à zéroUn programme qui appelle l'initialisation par défaut ou l'initialisation de valeur d'une entité de type référence est mal formé. Si T est un type qualifié cv, la version non qualifiée cv de T est utilisée pour ces définitions d'initialisation zéro, d'initialisation par défaut et d'initialisation de valeur.