2009-10-09 12 views
5

Ich habe den folgenden Code:Zwei Möglichkeiten des Standardkonstruktors Aufruf

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; 
} 

Wenn ich Programm (VS2008, debug) beginnen Ich habe die folgende Ausgabe:

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

Wie Sie b1 sehen können. x und b1.y haben einen Wert von 0. Warum? Was ist der Unterschied zwischen init1 und init2?

Wenn ich Kommentar- B Konstruktor ich die folgende Ausgabe haben:

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

Kann jemand den Grund für dieses Verhalten erklären? Tnx im Voraus.

Antwort

10

Der Standardkonstruktor für POD-Typen füllt ihn mit Nullen. Wenn Sie explizit Ihren eigenen Konstruktor definieren, initialisieren Sie nicht x und y und Sie erhalten zufällige Werte (in VS Debug sind sie mit genauen Werten gefüllt, aber in der Veröffentlichung werden sie zufällig sein).

Es ist nach C++ 03 Standard-8,5/5:

< ...> Um Wert initialisieren ein Objekt vom Typ T bedeutet:
- wenn T ein Klassentyp ist (Klausel 9) mit einem benutzerdeklarierten Konstruktor (12.1), dann wird der Standardkonstruktor für T aufgerufen (und die Initialisierung ist schlecht ausgebildet, wenn T keinen zugänglichen Standardkonstruktor hat);
- Wenn T ein Nicht-Vereinigungsklassen-Typ ohne einen von einem Benutzer deklarierten Konstruktor ist, dann wird jeder nicht-statische Daten-Member und Basis-Klassen-Komponente von T value-initialisiert;
- wenn T ein Array-Typ ist, dann wird jedes Element value-initialisiert;
- andernfalls ist das Objekt Null initialisiert.

B() ist eine Wert-Initialisierung von temporären, die in Kopie-Initialisierung von b1 verwendet werden.

In B b2 gibt es keine Initialisierer für ein Objekt spezifiziert, so dass nach C++ Standard-03 8,5/9:

Wenn kein Initialisierer für ein Objekt angegeben ist, und das Objekt ist von (möglicherweise cv-qualifiziert) Nicht-POD-Klassentyp (oder Array davon), das Objekt wird standardmäßig initialisiert; Wenn das Objekt vom Typ const-qualifiziert ist, muss der zugrunde liegende Klassentyp einen vom Benutzer deklarierten Standardkonstruktor haben. Wenn kein Initialisierer für ein nicht statisches Objekt angegeben ist, haben das Objekt und die zugehörigen Unterobjekte (falls vorhanden) einen unbestimmten Anfangswert; Wenn das Objekt oder eines seiner Unterobjekte vom Typ const qualifiziert ist, ist das Programm schlecht formatiert.

Um Nullen für b2 zu erhalten, könnten Sie B b2 = {}; schreiben.

+0

Wie erklärt dies die verschiedenen Ergebnisse für 'b1' und' b2'? – sth

+0

Und der letzte Fall für "default-initialize" sollte sein "andernfalls wird keine Initialisierung durchgeführt." Das ist der entscheidende Unterschied hier. – sth

+1

@sth: Nein, default-initalisierung muss andere Objekte zero-initialisieren, der entscheidende Punkt ist, dass POD-Typen mit automatischer Speicherdauer ohne expliziten Initialisierer nicht einmal default-initialisiert werden. –

2

Die O werden von Kirill erklärt

Der andere Wert: -858993460 ist 0xCCCCCCCC, die der Standardwert für nicht initialisierte Stapelspeicher in VC Debug-Builds ist.

Nicht initialisiert Heap Speicher standardmäßig auf 0xCDCDCDCD. Und natürlich sind die Standardinhalte in Release-Builds zufällig.

Nun muss ich zugeben, dass ich nicht weiß, dass es legal eine c'tor direkt anzurufen, wie Sie in Ihrem Beispiel zu tun! Und ich hätte geschworen, dass das illegal ist ...

+0

Nitpicking: 0xCC ist der Standardwert für nicht initialisierten ** Stack ** Speicher in VC Debug Build. Uninitialized ** Heap ** Speicher enthält 0xCD – sbk

0

ich versuchte auf vc6 und Visual Studio 2005 ich bekomme unten Ergebnis in beiden: Könnten Sie bitte disassemble Code erstellen, wie unten ich habe disassemble Code für 2005

veröffentlicht

x: -858993460

y: -858993460


x: -858993460

y: -858.993.460


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

Also, was ist der Grund für den Unterschied? Zuweisungsoperatoren sind außerhalb des Themas, da sie nicht aufgerufen werden. Destruktoren sind auch außerhalb des Themas. Es gibt eine Menge Text in Ihrem Beitrag, aber keine klare Antwort. –

+0

@ Alex, danke für den Kommentar, ich nahm an, dass operator = hieß, aber nach deinem Kommentar habe ich überprüft, dass es überhaupt nicht aufgerufen wird, lass mich testen, werde bald antworten :) – Satbir

3

Dies ist Wert-Initialisierung im Vergleich zu keiner Initialisierung. Wenn Sie

B b1 = B(); 

schreiben erhalten Sie copy-Initialisierung mit einem "Wert initialisiert" temporary - B(). Wert-Initialisierung von Klassen-Typ-Objekten ruft einen benutzerdefinierten Konstruktor auf (falls vorhanden) oder initialisiert value-initialisiert die Mitglieder. Die Wert-Initialisierung von Objekten vom Skalartyp entspricht der Null-Initialisierung. Wenn Sie einen eigenen Konstruktor deklarieren, der nichts bewirkt, werden Ihre Skalarelemente nicht initialisiert.

B b1; 

ist eine Standard-Initialisierung oder keine Initialisierung (abhängig von B).

Die genaue Initialisierung Regeln sind ziemlich kompliziert. Siehe C++ - Standard Abschnitt 8.5 "Initialisierer".

5

In beiden Fällen definiert diese Aussage b1 und copy-intializes es von einem Wert initialisierten temporären B Objekt.

B b1 = B(); 

Wenn B einen Benutzer nicht deklarierten Konstruktor, Wert-Initialisierung verursacht Aufruf von B ‚s Mitglieder wert initialisiert und für einfache Typen sein, wie int, bedeutet dies, Nullinitialisierung.

Wenn B hat einen Benutzer deklariert Konstruktor, Wert-Initialisierung versucht, den Standardkonstruktor aufzurufen. Wenn die Mitglieder x und y sind nicht im Konstruktor Initialisiererliste aufgeführt sind, dann sind sie nicht initialisierten links.

B b2; 

In Funktionen, lokale Objekte von POD-Typ ohne Initialisierer sind nicht initialisierten links.Wenn Sie keinen Konstruktor für B definieren, handelt es sich um eine POD-Klasse. Dies gilt, und die Werte b2.x und b2.y haben unbestimmte Werte.

Wenn das Objekt vom Nicht-POD-Klassentyp ist, ist es default-initialized, aber wenn dies einen Konstruktor aufruft, der seine Mitglieder nicht initialisiert, dann macht dies keinen Unterschied.

+0

Meinst du das im ersten Fall Sowohl Kopier- als auch Standardkonstruktoren werden aufgerufen? –

+0

Nominal, ja, aber der Compiler darf die Kopie optimieren. In diesem Fall könnte es direkt _value-initialize_ 'b1' sein. Was auch immer der Compiler wählt, der beobachtbare Effekt (für das Programm) muss derselbe sein. –

+0

Vielen Dank für die Erklärung. –

Verwandte Themen