Inizializzazione del membro POD della classe C++11 VS2013

Inizializzazione del membro POD della classe C++11 VS2013


Ho cercato dappertutto una spiegazione per questo, ma sto arrivando a breve. Vedo questo comportamento dal set di strumenti della piattaforma VS2013 v120, ma quando imposto il set di strumenti su v90 (il set di strumenti VS2008) tutto non è inizializzato. Credo che ciò sia dovuto a qualche cambiamento in C++11, ma potrebbe anche essere un'anomalia del set di strumenti della piattaforma v120.


Qualcuno può spiegare cosa sta succedendo qui a livello C++/C++11? Cioè, perché è b azzerato? E perché j non anche azzerato? (ovvero perché il comportamento è diverso per le strutture rispetto alle classi)


Inoltre, so che il modo in cui sto emettendo i dati è un comportamento indefinito, per favore ignoralo. È più facile pubblicare in questo modo qui rispetto a una finestra del debugger. Questo è in esecuzione a 32 bit, quindi i puntatori hanno le stesse dimensioni di un int non firmato.


Considera il seguente codice:


#include <iostream>
class Foo {
public:
int a,
*p;
};
class Bar {
public:
Bar(){}
int a,
*p;
};
struct Jar {
Jar(){}
int a,
*p;
};
int main() {
Foo f;
Bar b;
Jar j;
std::cout << std::hex; // please excuse this undefined-behavior producing test code, it's more simple to show this than a debugger window on SO (this is on 32-bit)
std::cout << "f: " << ((unsigned*)&f)[0] << ' ' << ((unsigned*)&f)[1] << std::endl;
std::cout << "b: " << ((unsigned*)&b)[0] << ' ' << ((unsigned*)&b)[1] << std::endl;
std::cout << "j: " << ((unsigned*)&j)[0] << ' ' << ((unsigned*)&j)[1] << std::endl;
return 0;
}

Questo è l'output:


f: cccccccc cccccccc  
b: 0 0
j: cccccccc cccccccc

MODIFICA:

Ecco lo smontaggio che vedo associato a Bar b; __autoclassinit2 sta azzerando la memoria. Non fa parte del costruttore ma viene azzerato prima della chiamata del costruttore.


  Bar b;
00886598 push 8
0088659A lea ecx,[b]
0088659D call Bar::__autoclassinit2 (0881181h)
008865A2 lea ecx,[b]
008865A5 call Bar::Bar (0881109h)

Risposte:


Tutti i tuoi tipi contengono membri dati che sono tipi predefiniti, quindi nessuno di essi verrà inizializzato a zero a meno che tu non esegua una delle seguenti operazioni (prendendo l'esempio di Foo ):


Inizializza i membri nel costruttore predefinito:


class Foo {
public:
Foo() : a(), p() {}
int a,
*p;
};

o inizializzatori di membri dati non statici (inizializzatore parentesi graffa o uguale )


class Foo {
public:
int a = 0,
*p = nullptr;
};

o lascia Foo invariato e il valore inizializza l'istanza


Foo f{};


Utilizzando l'esempio originale, non riesco a riprodurre il risultato che osservi utilizzando VS2013, build di debug a 32 bit. L'output che ottengo è


f: cccccccc cccccccc
b: cccccccc cccccccc
j: cccccccc cccccccc


MODIFICA : Sono in grado di riprodurre il comportamento in cui b viene inizializzato a zero. Ciò accade se abiliti il ​​/sdl (Controlli del ciclo di vita dello sviluppo della sicurezza ) opzione del compilatore (in Proprietà di configurazione -> C/C++ -> Generale).


Dalla documentazione MSDN per lo switch:



Questo post del blog menziona persino il __autoclassinit funzione, sebbene l'euristica che elenca non corrisponda esattamente a ciò che stiamo osservando perché il comportamento di questa funzione è cambiato tra VS2012 e VS2013.


Inoltre, non vale niente è che il compilatore sembra non solo distinguere tra aggregati (Foo ) e non aggregati (gli altri due), il che ha un senso, ma, per qualche motivo davvero bizzarro, eseguirà questa inizializzazione zero solo se usi la class-key class , e non struct , nella definizione della classe.


Alcune risposte al codice


#include <iostream>
class Foo { public: int a,
*p;
};
class Bar { public: Bar(){} int a,
*p;
};
struct Jar { Jar(){} int a,
*p;
};
int main() { Foo f;
Bar b;
Jar j;
std::cout <<
std::hex;
// please excuse this undefined-behavior producing test code, it's more simple to show this than a debugger window on SO (this is on 32-bit) std::cout <<
"f: " <<
((unsigned*)&f)[0] <<
' ' <<
((unsigned*)&f)[1] <<
std::endl;
std::cout <<
"b: " <<
((unsigned*)&b)[0] <<
' ' <<
((unsigned*)&b)[1] <<
std::endl;
std::cout <<
"j: " <<
((unsigned*)&j)[0] <<
' ' <<
((unsigned*)&j)[1] <<
std::endl;
return 0;
}
f: cccccccc cccccccc   b: 0 0   j: cccccccc cccccccc 
  Bar b;
00886598 push
8 0088659A lea
ecx,[b] 0088659D call
Bar::__autoclassinit2 (0881181h) 008865A2 lea
ecx,[b] 008865A5 call
Bar::Bar (0881109h)
class Foo { public:   Foo() : a(), p() {}   int a,
*p;
};
class Foo { public:   int a = 0,
*p = nullptr;
};
Foo f{};
f: cccccccc cccccccc b: cccccccc cccccccc j: cccccccc cccccccc