web-dev-qa-db-fra.com

Le constructeur par défaut initialise-t-il les types intégrés?

Le constructeur par défaut (créé par le compilateur) initialise-t-il les types intégrés?

162
Siggi

Le constructeur par défaut d'une classe défini implicitement (par le compilateur) n'initialise pas les membres des types intégrés.

Cependant, vous devez garder à l'esprit que dans certains cas, l'initialisation d'une instance de la classe peut être effectuée par d'autres moyens. Pas par défaut constructeur, ni par constructeur du tout.

Par exemple, il existe une croyance erronée largement répandue selon laquelle, pour la classe C, la syntaxe C() appelle toujours le constructeur par défaut. En réalité cependant, la syntaxe C() exécute ce que l'on appelle initialisation de la valeur de l'instance de la classe. Il n'appellera le constructeur par défaut que s'il est déclaré par l'utilisateur. (C'est en C++ 03. En C++ 98 - seulement si la classe est non-POD). Si la classe n'a pas de constructeur déclaré par l'utilisateur, la C() n'appelle pas le constructeur par défaut fourni par le compilateur, mais effectue plutôt un type d'initialisation spécial n'impliquant pas le constructeur de C du tout. Au lieu de cela, il initialisera directement chaque membre de la classe. Pour les types intégrés, l'initialisation est nulle.

Par exemple, si votre classe n'a pas de constructeur déclaré par l'utilisateur

class C { 
  int x;
};

alors le compilateur en fournira implicitement un. Le constructeur fourni par le compilateur ne fera rien, ce qui signifie qu'il n'initialisera pas C::x

C c; // Compiler-provided default constructor is used
// Here `c.x` contains garbage

Néanmoins, les initialisations suivantes will zero-initialize x car elles utilisent l'initialisateur explicite ()

C c = C(); // Does not use default constructor for `C()` part
           // Uses value-initialization feature instead
assert(c.x == 0);

C *pc = new C(); // Does not use default constructor for `C()` part
                 // Uses value-initialization feature instead
assert(pc->x == 0);

Le comportement de () initializer diffère à certains égards entre C++ 98 et C++ 03, mais pas dans ce cas. Pour la classe ci-dessus C, ce sera la même chose: () l'initialiseur effectue l'initialisation à zéro de C::x.

Un autre exemple d’initialisation réalisé sans constructeur est, bien sûr, l’initialisation globale.

C c = {}; // Does not use any `C` constructors at all. Same as C c{}; in C++11.
assert(c.x == 0);

C d{}; // C++11 style aggregate initialization.
assert(d.x == 0);
163
AnT

À toutes fins pratiques - non.


Cependant, pour les implémentations techniquement conformes à la norme C++, la réponse est que cela dépend du fait que l'objet est POD ou non et de la manière dont vous l'initialisez. Selon le standard C++:

MyNonPodClass instance1;//built in members will not be initialized
MyPodClass instance2;//built in members will be not be initialized
MyPodClass* instance3 = new MyPodClass;//built in members will not be initialized
MyPodClass* instance3 = new MyPodClass() ;//built in members will be zero initialized

Cependant, dans le monde réel, cela n'est pas bien supporté, alors ne l'utilisez pas.


Les parties pertinentes de la norme sont les sections 8.5.5 et 8.5.7.

18
JoeG

Je ne suis pas certain de ce que vous voulez dire, mais:

struct A { int x; };

int a; // a is initialized to 0
A b;   // b.x is initialized to 0

int main() {
    int c;         // c is not initialized
    int d = int(); // d is initialized to 0

    A e;           // e.x is not initialized
    A f = A();     // f.x is initialized to 0
}

Dans chaque cas où je dis "non initialisé", vous constaterez peut-être que votre compilateur lui donne une valeur cohérente, mais que la norme ne l'exige pas.

Beaucoup de gestes de la main se font entendre, y compris par moi-même, sur la manière dont les types intégrés "en effet" ont un constructeur par défaut. En fait, l'initialisation par défaut et l'initialisation de la valeur sont des termes définis dans la norme, que je dois personnellement rechercher à chaque fois. Seules les classes sont définies dans la norme pour avoir un constructeur implicite par défaut.

17
Steve Jessop

Comme les orateurs précédents l'ont dit - non, ils ne sont pas initialisés.

C'est en fait une source d'erreurs vraiment étranges, car les systèmes d'exploitation modernes ont tendance à remplir de zéros les régions de mémoire nouvellement allouées. Si vous vous attendez à cela, cela pourrait fonctionner la première fois. Cependant, au fur et à mesure que votre application continue à fonctionner, deleteing et newing, vous vous retrouverez tôt ou tard dans une situation dans laquelle vous vous attendez à des zéros, mais à des restes non nuls. l'objet est assis.

Alors, pourquoi est-ce alors que toutes les données new- ed ne sont pas nouvellement allouées? Oui, mais pas toujours depuis le système d'exploitation. Le système d'exploitation a tendance à fonctionner avec de gros morceaux de mémoire (par exemple, 4 Mo à la fois), de sorte que toutes les minuscules affectations et désallocations d'un mot-ici-trois-octets-là sont traitées dans l'espace uysers et ne sont donc pas mises à zéro.

PS J'ai écrit "tendance à", c'est-à-dire que vous ne pouvez même pas compter sur le succès la première fois ...

1
e8johan

Conformément à la norme, il ne le fait pas sauf si vous initialisez explicitement dans la liste des initialiseurs.

1
mukeshkumar