2009-10-09 5 views
5

j'ai le code suivant:Deux façons d'appeler le constructeur par défaut

struct B 
{ 
//B() {} 
int x; 
int y; 
}; 

void print(const B &b) 
{ 
std::cout<<"x:"<<b.x<<std::endl; 
std::cout<<"y:"<<b.y<<std::endl; 
std::cout<<"--------"<<std::endl; 
} 

int main() 
{ 
B b1 = B(); //init1 
B b2; //init2 

print(b1); 
print(b2); 

return 0; 
} 

Quand je commence le programme (VS2008, debug) J'ai la sortie suivante:

x:0 
y:0 
-------- 
x:-858993460 
y:-858993460 
-------- 

Comme vous pouvez le voir b1. x et b1.y ont 0 valeur. Pourquoi? Quelle est la différence entre init1 et init2?

Quand je décommenter constructeur B je la sortie suivante:

x:-858993460 
y:-858993460 
-------- 
x:-858993460 
y:-858993460 
-------- 

quelqu'un peut-il expliquer la raison de ce comportement? Tnx à l'avance.

Répondre

10

Le constructeur par défaut pour les types POD le remplit de zéros. Lorsque vous définissez explicitement votre propre constructeur, vous n'initialisez pas x et y et vous obtiendrez des valeurs aléatoires (dans le débogage VS ils sont remplis avec des valeurs exactes, mais en version ils seront aléatoires).

Il est conforme à la norme 03 C++ 8,5/5:

< ...> Pour initialiser la valeur un objet de type T désigne:
- si T est un type de classe (clause 9) avec un constructeur déclaré par l'utilisateur (12.1), le constructeur par défaut de T est appelé (et l'initialisation est mal formée 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 chaque composant de classe de base de T est initialisé en valeur;
- si T est un type de tableau, chaque élément est initialisé en valeur;
- sinon, l'objet est zéro initialisé.

B() est une valeur d'initialisation du temporaire qui sera utilisé dans la copie de l'initialisation b1.

Dans B b2 il n'y a pas d'initialisation spécifiée pour un objet, de sorte que selon la norme C++ 03 8,5/9:

Si aucun initialiseur est spécifié pour un objet, et l'objet est de (le type de classe non-POD (ou le tableau de ceux-ci), l'objet doit être initialisé par défaut; Si l'objet est de type const-qualifié, le type de classe sous-jacent doit avoir un constructeur par défaut déclaré par l'utilisateur. Sinon, si aucun initialiseur n'est spécifié pour un objet non statique, l'objet et ses sous-objets, le cas échéant, ont une valeur initiale indéterminée; si l'objet ou l'un de ses sous-objets sont de type const-qualifié, le programme est mal formé.

Pour obtenir des zéros pour b2 vous pouvez écrire B b2 = {};.

+0

Comment cela explique-t-il les différents résultats de 'b1' et' b2'? – sth

+0

Et le dernier cas pour "default-initialize" devrait être "sinon, aucune initialisation n'est effectuée." C'est la différence cruciale ici. – sth

+1

@sth: Non, default-initalize doit réinitialiser les autres objets, le point crucial est que les types POD avec une durée de stockage automatique sans initialiseur explicite ne sont même pas initialisés par défaut. –

2

Années de O sont expliqués par Kirill

L'autre valeur: -858993460 est 0xCCCCCCCC, qui est la valeur par défaut pour la pile de mémoire non initialisée dans la mise au point de VC construit.

Non initialisé tas la mémoire par défaut à 0xCDCDCDCD. Et bien sûr, dans les versions de versions, le contenu par défaut est aléatoire.

Maintenant, je dois admettre que je ne savais pas qu'il est légal d'appeler un c'tor directement comme vous le faites dans votre exemple! Et j'aurais juré que c'est illégal ...

+0

nitpicking: 0xCC est la valeur par défaut de la mémoire ** stack ** non initialisée dans la version de débogage VC. Mémoire ** heap ** non initialisée contiendra 0xCD – sbk

0

j'ai essayé sur vc6 et Visual Studio 2005 je reçois ci-dessous résultat dans les deux: Pourriez-vous s'il vous plaît poste démonter le code généré, Comme ci-dessous j'ai posté le code de désassemblage pour 2005

x: -858993460

y: -858993460


x: -858993460

y: -858993460


B b1 = B(); //init1 
0043DEDE lea   ecx,[b1] 
0043DEE1 call  B::B (43ADD9h) 
B b2; //init2 
0043DEE6 lea   ecx,[b2] 
0043DEE9 call  B::B (43ADD9h) 

print(b1); 
0043DEEE lea   eax,[b1] 
0043DEF1 push  eax 
0043DEF2 call  print (43A302h) 
0043DEF7 add   esp,4 
print(b2); 
0043DEFA lea   eax,[b2] 
0043DEFD push  eax 
0043DEFE call  print (43A302h) 
0043DF03 add   esp,4 
+0

Alors, quelle est la raison de la différence? Les opérateurs d'affectation sont hors sujet car ils ne sont pas appelés. Les destructeurs sont également hors sujet. Il y a beaucoup de texte dans votre message, mais pas de réponse claire. –

+0

@ Alex, merci pour le commentaire, j'ai supposé que opeator = a été appelé, Mais après votre commentaire j'ai vérifié qu'il n'est pas appelé du tout, Laissez-moi faire un test, répondra bientôt :) – Satbir

3

Ceci est la valeur d'initialisation par rapport à aucune initialisation. Si vous écrivez

B b1 = B(); 

vous obtenez une copie-initialisation avec une "valeur initialisée" temporaire - B(). L'initialisation de la valeur d'objets de type classe appelle un constructeur défini par l'utilisateur (s'il existe) ou initialise la valeur des membres. L'initialisation de la valeur des objets de type scalaire est équivalente à l'initialisation zéro. Lorsque vous déclarez votre propre constructeur qui ne fait rien, vos membres scalaires ne sont pas initialisés.

B b1; 

est une initialisation par défaut ou aucune initialisation (selon B).

Les règles d'initialisation exactes sont assez compliquées. Voir la section 8.5 "Initializers" de la norme C++.

5

Dans les deux cas, cette déclaration définit b1 et copie-intializes à partir d'une valeur initialisée temporaire objet B.

B b1 = B(); 

Lorsque B n'a pas un constructeur déclaré utilisateur, valeur d'initialisation provoque l'appel des membres de B être valeur initalized, et pour les types simples, tels que int, ce moyen l'initialisation du zéro.

Lorsque B a un constructeur déclaré par l'utilisateur, l'initialisation de la valeur essaie d'appeler le constructeur par défaut. Si les membres x et y ne sont pas répertoriés dans la liste d'initialisation du constructeur, ils ne sont pas initialisés.

B b2; 

Dans les fonctions, les objets locaux de type POD sans initialiseur sont laissés non initialisés.Lorsque vous ne définissez pas de constructeur pour B, il s'agit d'une classe POD. Cela s'applique donc et les valeurs b2.x et b2.y ont des valeurs indéterminées.

Si l'objet est de type classe non-POD, il est par défaut initialisé, mais si cela appelle un constructeur qui laisse ses membres non initialisée alors cela ne fait aucune différence.

+0

Voulez-vous dire que dans le premier cas les constructeurs de copie et par défaut sont appelés? –

+0

Nominalement, oui, mais le compilateur est autorisé à optimiser la copie. Dans ce cas, il pourrait directement _value-initialize_ 'b1'. Quoi que le compilateur choisisse de faire, l'effet observable (pour le programme) doit être le même. –

+0

Merci pour l'explication. –

Questions connexes