¿Qué significan las siguientes frases en C ++: inicialización de cero, predeterminada y de valor?

190

¿Qué significan las siguientes frases en C ++:

  • inicialización cero,

  • inicialización predeterminada y

  • inicialización de valor

¿Qué debe saber un desarrollador de C ++ sobre ellos?

Cuenta
fuente
1
Esto está relacionado con (pero no idéntico a) stackoverflow.com/questions/620137/…
Steve Jessop
20
¡Hay más! La lista completa de inicializaciones: Valor, directo, copia, lista (introducción nueva de C ++ 11), agregado, referencia, cero, constante y predeterminado; en.cppreference.com/w/cpp/language/initialization enumera todos ellos con ejemplos :)
legends2k

Respuestas:

65

Una cosa a tener en cuenta es que la 'inicialización del valor' es nueva con el estándar C ++ 2003: no existe en el estándar original de 1998 (creo que podría ser la única diferencia que es más que una aclaración). Ver la respuesta de Kirill V. Lyadvinsky para las definiciones directamente del estándar.

Consulte esta respuesta anterior sobre el comportamiento de operator newpara obtener detalles sobre el comportamiento diferente de este tipo de inicialización y cuándo entran en acción (y cuando difieren de c ++ 98 a C ++ 03):

El punto principal de la respuesta es:

A veces, la memoria devuelta por el nuevo operador se inicializará, y a veces no dependerá de si el tipo que está renovando es un POD, o si es una clase que contiene miembros de POD y está utilizando un constructor predeterminado generado por el compilador .

  • En C ++ 1998 hay 2 tipos de inicialización: cero y predeterminado
  • En C ++ 2003, un tercer tipo de inicialización, se agregó la inicialización de valor.

Por decir lo menos, es bastante complejo y cuando los diferentes métodos entran en juego son sutiles.

Una cosa a tener en cuenta es que MSVC sigue las reglas de C ++ 98, incluso en VS 2008 (VC 9 o cl.exe versión 15.x).

El siguiente fragmento muestra que MSVC y Digital Mars siguen las reglas de C ++ 98, mientras que GCC 3.4.5 y Comeau siguen las reglas de C ++ 03:

#include <cstdio>
#include <cstring>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    std::printf( "m  is %d\n", pB->m);
    return 0;
}
Michael Burr
fuente
1
No es que importe int, pero m()en la tercera línea el valor inicializa m. Importante si cambias int m;a B m;. :)
Johannes Schaub - litb
Correcto, Ay Cno se usan en este ejemplo (se transfieren de la otra respuesta vinculada). Aunque C ++ 98 y C ++ 03 usan una terminología diferente al describir cómo Ay Cse construyen, el resultado es el mismo en ambos estándares. Solo struct Bda como resultado un comportamiento diferente.
Michael Burr
1
lo que quise decir es que si cambia C a struct C { C() : m() {}; ~C(); B m; };, entonces tendrá m.m0. Pero si se inicializa por defecto mcomo dice C ++ 03, entonces m.mno se inicializaría como en C ++ 98.
Johannes Schaub - litb
1
Comentarios interesantes adicionales sobre el manejo de MSVC de esta característica: stackoverflow.com/questions/3931312/…
Brent Bradburn
¿Qué inicialización tiene lugar cuando declara su tipo como una variable local, es decir, en la pila?
André Puel
89

C ++ 03 Estándar 8.5 / 5:

Inicializar a cero un objeto de tipo T significa:
- si T es un tipo escalar (3.9), el objeto se establece en el valor de 0 (cero) convertido a T;
- si T es un tipo de clase no sindical, cada miembro de datos no estático y cada subobjeto de clase base se inicializa en cero;
- si T es un tipo de unión, el primer miembro de datos nombrado del objeto se inicializa en cero;
- si T es un tipo de matriz, cada elemento tiene inicialización cero;
- si T es un tipo de referencia, no se realiza ninguna inicialización.

Para default-inicializar un objeto de medios de tipo T:
- si T es a-POD no tipo de clase (cláusula 9), el constructor predeterminado de T se llama (y está mal formada la inicialización si T no tiene constructor predeterminado accesible);
- si T es un tipo de matriz, cada elemento se inicializa por defecto;
- de lo contrario, el objeto está inicializado en cero.

Para valor-inicializar un objeto de medios de tipo T:
- si T es un tipo de clase (cláusula 9) con un constructor-declarado de usuario (12.1), entonces el constructor predeterminado de T se llama (y la inicialización está mal formada si T no tiene un constructor predeterminado accesible);
- si T es un tipo de clase sin unión sin un constructor declarado por el usuario, entonces cada miembro de datos no estático y componente de clase base de T tiene un valor inicializado;
- si T es un tipo de matriz, entonces cada elemento tiene un valor inicializado;
- de lo contrario, el objeto está inicializado en cero

Un programa que requiere inicialización predeterminada o inicialización de valor de una entidad de tipo de referencia está mal formado. Si T es un tipo calificado para cv, la versión no calificada de cv de T se usa para estas definiciones de inicialización cero, inicialización predeterminada e inicialización de valor.

Kirill V. Lyadvinsky
fuente
18
Esto podría estar desactualizado para C ++ 11. cppreference.com establece que la inicialización predeterminada no inicializa a los miembros (solo lo hace la inicialización de valor).
Alexei Sholik
3
@android plantea un punto importante, que no veo respondido en otra parte, así que hice una nueva pregunta. stackoverflow.com/questions/22233148/…
Adrian McCarthy