Selon la réponse acceptée (et unique) pour cette question Stack Overflow ,
Définition du constructeur avec
MyTest() = default;
va à la place initialiser l'objet à zéro.
Alors pourquoi ce qui suit,
#include <iostream>
struct foo {
foo() = default;
int a;
};
struct bar {
bar();
int b;
};
bar::bar() = default;
int main() {
foo a{};
bar b{};
std::cout << a.a << ' ' << b.b;
}
produire cette sortie:
0 32766
Les deux constructeurs définis sont par défaut? Droite? Et pour les types POD, l'initialisation par défaut est zéro-initialisation.
Et selon la réponse acceptée pour cette question ,
Si un membre POD n'est pas initialisé dans le constructeur ni via l'initialisation en classe C ++ 11, il est initialisé par défaut.
La réponse est la même quelle que soit la pile ou le tas.
Dans C ++ 98 (et pas après), new int () a été spécifié comme effectuant une initialisation zéro.
Bien que j'aie essayé d'envelopper ma tête (quoique minuscule ) autour des constructeurs par défaut et de l' initialisation par défaut , je n'ai pas pu trouver d'explication.
la source
bar
Le constructeur de est fourni par l'utilisateur alors quefoo
le constructeur de est celui par défaut.a
est zéro.b
n'est pas. Semblea
est initialisé.bar::bar()
soit visible dansmain()
- il pourrait être défini dans une unité de compilation séparée et faire quelque chose de très non trivial alors quemain()
seule la déclaration est visible. Je pense que vous conviendrez que ce comportement ne devrait pas changer selon que vous placezbar::bar()
la définition de dans une unité de compilation distincte ou non (même si la situation dans son ensemble n'est pas intuitive).int a = 0;
voulez-vous être vraiment explicite.Réponses:
Le problème ici est assez subtil. Vous penseriez que
vous donnerait un constructeur par défaut généré par le compilateur, et c'est le cas, mais il est maintenant considéré comme fourni par l'utilisateur. [dcl.fct.def.default] / 5 déclare:
accent le mien
Nous pouvons donc voir que, puisque vous n'avez pas défini la valeur par défaut
bar()
lors de la première déclaration, il est désormais considéré comme fourni par l'utilisateur. A cause de cela [dcl.init] /8.2ne s'applique plus et nous ne valorisons pas l'initialisation
b
mais l'initialisation par défaut par [dcl.init] /8.1la source
(*_*)
... Si même pour utiliser les constructions de base de la langue, j'ai besoin de lire les petits caractères du brouillon de langue, alors Alléluia! Mais cela semble probablement être ce que vous dites.bar::bar() = default
hors ligne équivaut à faire enbar::bar(){}
ligne.La différence de comportement vient du fait que, selon
[dcl.fct.def.default]/5
,bar::bar
est fourni par l'utilisateur oùfoo::foo
n'est pas 1 . En conséquence,foo::foo
sera la valeur-initialiser ses membres ( ce qui signifie: zéro initializefoo::a
) maisbar::bar
restera non initialisé 2 .1)
[dcl.fct.def.default]/5
2)
D'après la réponse de Vittorio Romeo
la source
De cppreference :
Compte tenu de cette définition,
foo
est un agrégat, tandis quebar
ne l'est pas (il a un constructeur non défini par défaut fourni par l'utilisateur).Par conséquent, pour
foo
,T object {arg1, arg2, ...};
est la syntaxe pour l'initialisation agrégée.La
a.a
valeur est donc initialisée, ce quiint
signifie une initialisation nulle.Car
bar
,T object {};
d'autre part, il y a l'initialisation de la valeur (de l'instance de classe, pas l'initialisation de la valeur des membres!). Puisqu'il s'agit d'un type de classe avec un constructeur par défaut, le constructeur par défaut est appelé. Le constructeur par défaut que vous avez défini par défaut initialise les membres (en raison de l'absence d'initialiseurs de membres), qui en cas deint
(avec stockage non statique) laisseb.b
avec une valeur indéterminée.Non, c'est faux.
PS Un mot sur votre expérience et votre conclusion: voir que la sortie est égale à zéro ne signifie pas nécessairement que la variable a été initialisée à zéro. Zéro est un nombre parfaitement possible pour une valeur de garbage.
Le fait que la valeur ait été la même plusieurs fois ne signifie pas nécessairement qu'elle a été initialisée non plus.
Le fait que le résultat soit le même avec plusieurs options du compilateur ne signifie pas que la variable est initialisée. (Bien que dans certains cas, le changement de version standard peut changer si elle est initialisée).
Il n'existe aucun moyen garanti en C ++ de faire apparaître une valeur de valeur non initialisée différente de zéro.
Le seul moyen de savoir qu'une variable est initialisée est de comparer le programme aux règles du langage et de vérifier que les règles disent qu'il est initialisé. Dans ce cas
a.a
est bien initialisé.la source
a
est initialisé. Je pensais que l'a
initialisation par défaut est initialisée par défaut et l'initialisation par défaut d'un POD membre est une initialisation zéro. Esta
donc heureusement toujours à zéro, peu importe combien de fois je lance ce programme.Then how come a is initialized.
Parce qu'il s'agit d'une valeur initialisée.I was thinking a is default initialized
Ce n'est pas.Meh, j'ai essayé d'exécuter l'extrait que vous avez fourni en tant que
test.cpp
, via gcc & clang et plusieurs niveaux d'optimisation:C'est donc là que ça devient intéressant, cela montre clairement que la construction clang O0 lit des nombres aléatoires, vraisemblablement de l'espace de pile.
J'ai rapidement consulté mon IDA pour voir ce qui se passait:
Maintenant, qu'est-ce que ça
bar::bar(bar *this)
fait?Hmm, rien. Nous avons dû recourir à l'assemblage:
Donc oui, c'est juste, rien, ce que le constructeur fait essentiellement
this = this
. Mais nous savons qu'il charge en fait des adresses de pile non initialisées aléatoires et les imprime.Et si nous fournissons explicitement des valeurs pour les deux structures?
Hit up clang, oopsie:
Destin similaire avec g ++ également:
Cela signifie donc que c'est effectivement une initialisation directe
bar b(0)
, pas une initialisation agrégée.C'est probablement parce que si vous ne fournissez pas d'implémentation de constructeur explicite, cela pourrait potentiellement être un symbole externe, par exemple:
Le compilateur n'est pas assez intelligent pour déduire cela comme un appel sans opération / en ligne dans une étape non optimisée.
la source