¿Los miembros de una estructura C ++ se inicializan a 0 de forma predeterminada?

201

Tengo esto struct:

struct Snapshot
{
    double x; 
    int y;
};

Quiero xy yser 0. ¿Serán 0 por defecto o tengo que hacer:

Snapshot s = {0,0};

¿Cuáles son las otras formas de poner a cero la estructura?

ks1322
fuente
Utilice un std :: map <> y devuelva 0 cuando no exista una clave.
Jonny
Tenga en cuenta que el uso de valores indeterminados es un comportamiento indefinido
Shafik Yaghmour

Respuestas:

264

No son nulos si no inicializa la estructura.

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

El segundo hará que todos los miembros sean cero, el primero los deja en valores no especificados. Tenga en cuenta que es recursivo:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

El segundo hará p.s.{x,y}cero. No puede usar estas listas de inicializadores agregados si tiene constructores en su estructura. Si ese es el caso, deberá agregar la inicialización adecuada a esos constructores

struct Snapshot {
    int x;
    double y;
    Snapshot():x(0),y(0) { }
    // other ctors / functions...
};

Inicializará tanto x como y a 0. Tenga en cuenta que puede usar x(), y()para inicializar sin tener en cuenta su tipo: esa es la inicialización del valor, y generalmente produce un valor inicial adecuado (0 para int, 0.0 para doble, llamando al constructor predeterminado para el usuario definido tipos que tienen constructores declarados por el usuario, ...). Esto es importante especialmente si su estructura es una plantilla.

Johannes Schaub - litb
fuente
1
Esto produce muchas advertencias en mi compilador.
River-Claire Williamson
1
Roger: Intente usar la estructura con nombre en el inicializador, eso es lo que hago y no recibo ninguna advertencia en VC 2012: Snapshot s = Snapshot ();
Kit10
@Johannes Schaub - litb ¿Funcionará Snapshot s = {};para los miembros que no son POD (por ponerlos a cero)?
ontherocks
2
C ++ 11 ahora le permite inicializarlos en la definición de la estructura o clase, de este modo: struct Snapshot {double x {0}; // con llaves int y = 0; // o simplemente el estilo de la vieja escuela 'por asignación' que también es realmente inicialización};
ikku100
1
Es "Instantánea s = {};" parte de la norma?
Stefan
41

No, no son 0 por defecto. La forma más sencilla de garantizar que todos los valores o predeterminados a 0 es definir un constructor

Snapshot() : x(0), y(0) {
}

Esto asegura que todos los usos de Snapshot tendrán valores inicializados.

JaredPar
fuente
24
La desventaja es que la estructura ya no es un tipo POD, porque tiene un constructor. Eso interrumpirá algunas operaciones, como escribirlo en un archivo temporal.
finnw 01 de
16
@finnw: C ++ 11 corrige esto, aunque la estructura no es POD, es "diseño estándar".
Ben Voigt
20

En general, no. Sin embargo, una estructura declarada como alcance de archivo o estática en una función / se inicializará a 0 (al igual que todas las demás variables de esos ámbitos):

int x; // 0
int y = 42; // 42
struct { int a, b; } foo; // 0, 0

void foo() {
  struct { int a, b; } bar; // undefined
  static struct { int c, d; } quux; // 0, 0
}
bdonlan
fuente
1
Eso realmente no es una suposición segura. no debe confiar en el valor de nada que no haya inicializado
Hasturkun
24
Los objetos de duración de almacenamiento estático siempre se inicializan a cero; consulte stackoverflow.com/questions/60653/… para obtener una cita del estándar. Si este es un buen estilo es otra cuestión.
bdonlan 01 de
12

Con POD también puedes escribir

Snapshot s = {};

No debe usar memset en C ++, memset tiene el inconveniente de que si hay un no POD en la estructura, lo destruirá.

o así:

struct init
{
  template <typename T>
  operator T * ()
  {
    return new T();
  }
};

Snapshot* s = init();
AndersK
fuente
@LightnessRacesinOrbit oh wat?
Ben Sinclair
@Andy Most Vexing Parse convierte cosas que se parecen a las herramientas normales ( SomeType foo();es la típica, aunque puede suceder con otras) en definiciones de funciones (en ese caso, una función fooque regresa SomeType). Perdón por el necro, pero si alguien más se encuentra con esto, pensé que respondería.
Financia la demanda de Mónica el
8

En C ++, use constructores sin argumentos. En C no puede tener constructores, así que use uno memseto la solución interesante: inicializadores designados:

struct Snapshot s = { .x = 0.0, .y = 0.0 };
Adrian Panasiuk
fuente
Creo que esto es C, no C ++. No se compilará en algunos compiladores de C ++. Experimenté la falla de compilación bajo Cygwin o MinGW.
jww
3

Creo que la respuesta correcta es que sus valores no están definidos. A menudo, se inicializan a 0 cuando se ejecutan versiones de depuración del código. Este no suele ser el caso cuando se ejecutan versiones de lanzamiento.

Eric
fuente
2
En realidad, las versiones de depuración ya tienen 0en esos lugares en la memoria. ¡Esto no es lo mismo que la inicialización!
ligereza corre en órbita el
3

Dado que este es un POD (esencialmente una estructura C), hay poco daño en inicializarlo de la manera C:

Snapshot s;
memset(&s, 0, sizeof (s));

o de manera similar

Snapshot *sp = new Snapshot;
memset(sp, 0, sizeof (*sp));

Sin embargo, no iría tan lejos como para usarlo calloc()en un programa C ++.

finnw
fuente
3
Lo mismo vale para el doble; all-bits-zero no es necesariamente 0.0. Sin embargo, puede verificar si tiene dobles IEEE754, en cuyo caso debe funcionar.
MSalters
1

Mueva los miembros del pod a una clase base para acortar su lista de inicializadores:

struct foo_pod
{
    int x;
    int y;
    int z;
};

struct foo : foo_pod
{
    std::string name;
    foo(std::string name)
        : foo_pod()
        , name(name)
    {
    }
};

int main()
{
    foo f("bar");
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str());
}
Bruno Martinez
fuente