Os membros de uma estrutura C ++ são inicializados em 0 por padrão?

200

Eu tenho isso struct:

struct Snapshot
{
    double x; 
    int y;
};

Eu quero xe yseja 0. Eles serão 0 por padrão ou eu tenho que fazer:

Snapshot s = {0,0};

Quais são as outras maneiras de zerar a estrutura?

ks1322
fonte
Use um std :: map <> e retorne 0 quando uma chave não existir.
Jonny

Respostas:

263

Eles não serão nulos se você não inicializar a estrutura.

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

O segundo fará com que todos os membros sejam zero, o primeiro os deixa com valores não especificados. Observe que é recursivo:

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

O segundo fará p.s.{x,y}zero. Você não pode usar essas listas agregadas de inicializadores se tiver construtores em sua estrutura. Se for esse o caso, você precisará adicionar uma initalização adequada a esses construtores

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

Inicializará x e y como 0. Observe que você pode usá x(), y()-lo para desconsiderar seu tipo: Isso é inicialização de valor e, geralmente, gera um valor inicial adequado (0 para int, 0,0 para double, chamando o construtor padrão para usuário definido tipos que possuem construtores declarados pelo usuário, ...). Isso é importante, especialmente se sua estrutura é um modelo.

Johannes Schaub - litb
fonte
1
Isso produz muitos avisos no meu compilador.
River-Claire Williamson
1
Roger: Tente usar a estrutura nomeada no inicializador, é o que eu faço e não recebo nenhum aviso no VC 2012: Snapshot s = Snapshot ();
precisa saber é o seguinte
@Johannes Schaub - litb Funcionará Snapshot s = {};para não membros do POD (para zerá-los)?
ontherocks 15/10
2
O C ++ 11 agora permite inicializá-los na definição da estrutura ou classe, assim: struct Snapshot {double x {0}; // com chaves int y = 0; // ou apenas o estilo da velha escola 'por atribuição', que também é realmente de inicialização};
Ikku100
1
É "Instantâneo s = {};" parte do padrão?
21418 Stefan
40

Não, eles não são 0 por padrão. A maneira mais simples de garantir que todos os valores ou o padrão seja 0 é definir um construtor

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

Isso garante que todos os usos do Snapshot tenham valores inicializados.

JaredPar
fonte
24
A desvantagem é que a estrutura não é mais um tipo de POD, porque possui um construtor. Isso interromperá algumas operações, como gravá-lo em um arquivo temporário.
#
16
@ finnw: C ++ 11 corrige isso, embora a estrutura não seja POD, é "layout padrão".
Ben Voigt
19

Em geral, não. No entanto, uma estrutura declarada como escopo do arquivo ou estática em uma função / será / inicializada em 0 (assim como todas as outras variáveis ​​desses escopos):

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
fonte
1
Isso realmente não é uma suposição segura. você não deve contar com o valor de qualquer coisa que você não inicializou
Hasturkun
24
Os objetos de duração de armazenamento estático são sempre inicializados em zero - consulte stackoverflow.com/questions/60653/… para obter uma citação do padrão. Se isso é bom estilo é outra questão.
bdonlan
12

Com POD você também pode escrever

Snapshot s = {};

Você não deve usar o memset em C ++, o memset tem a desvantagem de que, se houver um não-POD na estrutura, ele o destruirá.

ou assim:

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

Snapshot* s = init();
AndersK
fonte
@LightnessRacesinOrbit oh wat?
Ben Sinclair
@Andy A maioria dos vexing Parse transforma coisas que se parecem com citores normais - SomeType foo();é o típico, embora possa acontecer com outras pessoas - em definições de função (nesse caso, uma função fooque retorna SomeType). Sinto muito pelo necro, mas se alguém mais se deparar com isso, achei que eu responderia.
Fund Monica's Lawsuit
7

No C ++, use construtores sem argumento. Em C, você não pode ter construtores; portanto, use um memsetou - a solução interessante - inicializadores designados:

struct Snapshot s = { .x = 0.0, .y = 0.0 };
Adrian Panasiuk
fonte
Eu acredito que isso é C, não C ++. Falha ao compilar sob alguns compiladores C ++. Eu experimentei a falha de compilação sob Cygwin ou MinGW.
JWW
3

Acredito que a resposta correta é que seus valores são indefinidos. Geralmente, eles são inicializados como 0 ao executar versões de depuração do código. Geralmente, esse não é o caso ao executar versões de lançamento.

Eric
fonte
2
Na verdade, as versões de depuração já possuem 0esses lugares na memória. Isso não é o mesmo que inicialização!
Lightness Races in Orbit
3

Como este é um POD (essencialmente uma estrutura C), há pouco dano em inicializá-lo da maneira C:

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

ou similar

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

Eu não iria tão longe a ponto de usar calloc()em um programa C ++.

finnw
fonte
3
O mesmo vale para o dobro; all-bits-zero não é necessariamente 0.0. No entanto, você pode verificar se possui dobras IEEE754; nesse caso, ele deve funcionar.
MSalters
1

Mova os membros do pod para uma classe base para reduzir sua 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
fonte