25

El estándar y el libro en C++ dicen que el constructor predeterminado implícito generado llama al constructor predeterminado para los miembros del tipo de clase, pero los tipos incorporados no se inicializan. Sin embargo, en este programa de prueba consigo resultados inesperados cuando se asigna un objeto en el montón o cuando se utiliza un objeto temporal:¿Por qué un POD en una estructura inicializa cero mediante un constructor implícito al crear un objeto en el montón o un objeto temporal en la pila?

#include<iostream> 


struct Container 
{ 
    int n; 
}; 

int main() 
{ 
    Container c; 
    std::cout << "[STACK] Num: " << c.n << std::endl; 

    Container *pc = new Container(); 
    std::cout << "[HEAP] Num: " << pc->n << std::endl; 
    delete pc; 

    Container tc = Container(); 
    std::cout << "[TEMP] Num: " << tc.n << std::endl; 

} 

consigo esta salida:

[STACK] Num: -1079504552 
[HEAP] Num: 0 
[TEMP] Num: 0 

Es esto algún comportamiento específico del compilador? Realmente no tengo la intención de confiar en esto, pero tengo curiosidad por saber por qué sucede esto, especialmente para el tercer caso.

+0

posible duplicado de [Inicialización predeterminada de Struct en C++] (http://stackoverflow.com/questions/2951586/default-struct-initialization-in-c) – sharptooth

+1

Supongo que el montón se inicializa con ceros – davka

+1

Pensé lo mismo sobre el caso Heap, tal vez fue solo ceros por casualidad, pero me parece sorprendente el caso temporal objeto. –

Respuesta

40

Es el comportamiento esperado. Hay dos conceptos, "inicialización predeterminada" e "inicialización de valor". Si no menciona ningún inicializador, el objeto se "inicializará por defecto", mientras que si lo menciona, incluso como() para el constructor predeterminado, el objeto tiene "valor inicializado". Cuando se define el constructor, ambos casos llaman al constructor predeterminado. Pero para los tipos incorporados, la "inicialización del valor" pone a cero la memoria mientras que la "inicialización predeterminada" no lo hace.

Así que al inicializar:

Type x; 

se llamará constructor por defecto si se proporciona, pero quedará sin inicializar tipos primitivos. Sin embargo, cuando mencionas un inicializador, p.

Type x = {}; // only works for struct/class without constructor 
Type x = Type(); 
Type x{}; // C++11 only 

un tipo primitivo (o miembros primitivos de una estructura) serán VALOR-inicializado.

mismo modo para:

struct X { int x; X(); }; 

si se define el constructor

X::X() {} 

el miembro x será inicializado, pero si se define el constructor

X::X() : x() {} 

que será VALOR -inicializado Eso se aplica a new y, por lo

new int; 

debería darle la memoria sin inicializar, pero

new int(); 

debe darle la memoria inicializa a cero. Por desgracia, la sintaxis:

Type x(); 

no está permitido debido a la ambigüedad gramática y

Type x = Type(); 

está obligado a llamar constructor por defecto seguido por el constructor copia si ambos están especificados y no inlineable.

C++ 11 introduce nueva sintaxis,

Type x{}; 

que es utilizable para ambos casos. Si todavía está atascado con un estándar anterior, es por eso que hay Boost.ValueInitialized, por lo que puede inicializar correctamente la instancia del argumento de la plantilla.

Se puede encontrar una discusión más detallada, p. in Boost.ValueInitialized documentation.

+0

gran respuesta, pero ¿qué pasa con std :: make_unique (), va a valorar inicializar la variable? – tommyk

18

La respuesta corta es: el paréntesis vacío realiza value initialization.

En cambio, cuando diga Container *pc = new Container;, observará un comportamiento diferente.

+0

@FredOverflow, Derecha, pero mi gcc inicializa POD tipos a 0 con o sin paréntesis. – UmmaGumma

+1

@Ashot: Es una coincidencia, también ocurre en mi máquina. Solo crea un par más en el montón sin el paréntesis, y obtendrás diferentes valores. – fredoverflow

+1

@FredOverflow Justo después de asignar mucha memoria, finalmente obtengo datos distintos de cero :) Gracias. – UmmaGumma

Cuestiones relacionadas