O que as seguintes frases significam em C ++: inicialização com zero, padrão e valor?

188

O que as seguintes frases significam em C ++:

  • inicialização zero,

  • inicialização padrão e

  • inicialização de valor

O que um desenvolvedor de C ++ deve saber sobre eles?

Conta
fonte
1
Isto está relacionado com (mas não idêntico) stackoverflow.com/questions/620137/...
Steve Jessop
20
Tem mais! A lista completa de inicializações: Valor, direto, cópia, lista (nova introdução do C ++ 11), agregado, referência, zero, constante e padrão; en.cppreference.com/w/cpp/language/initialization listas Todos eles com exemplos :)
legends2k

Respostas:

64

Uma coisa a perceber é que a 'inicialização de valor' é nova no padrão C ++ 2003 - ela não existe no padrão original de 1998 (acho que pode ser a única diferença que é mais do que um esclarecimento). Veja a resposta de Kirill V. Lyadvinsky para as definições diretamente do padrão.

Consulte esta resposta anterior sobre o comportamento de operator newpara obter detalhes sobre os diferentes comportamentos desse tipo de inicialização e quando eles entram em ação (e quando diferem de c ++ 98 para C ++ 03):

O ponto principal da resposta é:

Às vezes, a memória retornada pelo novo operador será inicializada, e outras vezes, dependendo do tipo que você está iniciando, seja um POD ou se é uma classe que contém membros do POD e está usando um construtor padrão gerado pelo compilador .

  • No C ++ 1998, existem 2 tipos de inicialização: zero e padrão
  • No C ++ 2003, um terceiro tipo de inicialização foi adicionado à inicialização do valor.

Para dizer o mínimo, é bastante complexo e quando os diferentes métodos são sutis.

Certamente, é importante estar ciente de que o MSVC segue as regras do C ++ 98, mesmo no VS 2008 (VC 9 ou cl.exe versão 15.x).

O seguinte snippet mostra que o MSVC e o Digital Mars seguem as regras do C ++ 98, enquanto o GCC 3.4.5 e o Comeau seguem as regras do 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
fonte
1
Não que isso importe int, mas m()na terceira linha o valor inicializa m. Importante se você mudar int m;para B m;. :)
Johannes Schaub - litb 23/10/09
Certo - Ae Cnão são usados ​​neste exemplo (eles são herdados da outra resposta vinculada). Embora o C ++ 98 e o C ++ 03 usem terminologia diferente ao descrever como Ae Csão construídos, o resultado é o mesmo nos dois padrões. Apenas struct Bresulta em comportamento diferente.
22711 Michael Burr
1
o que eu quis dizer é que, se você alterar C para struct C { C() : m() {}; ~C(); B m; };, você terá m.m0. Mas, se inicializar mcomo padrão, como você diz C ++ 03, m.mnão será inicializado como em C ++ 98.
Johannes Schaub - litb 27/09/10
1
Comentários adicionais interessantes sobre o manuseio desse recurso pelo MSVC: stackoverflow.com/questions/3931312/…
nobar
Qual inicialização ocorre quando você declara seu tipo como uma variável local, ou seja, na pilha?
André Puel 21/03
87

Padrão C ++ 03 8.5 / 5:

Para inicializar com zero um objeto do tipo T significa:
- se T é um tipo escalar (3.9), o objeto é definido com o valor de 0 (zero) convertido em T;
- se T é um tipo de classe sem união, cada membro de dados não estático e cada subobjeto da classe base são inicializados com zero;
- se T é um tipo de união, o primeiro membro de dados nomeado do objeto é inicializado com zero;
- se T é um tipo de matriz, cada elemento é inicializado com zero;
- se T é um tipo de referência, nenhuma inicialização é executada.

Para inicializar por padrão um objeto do tipo T significa:
- se T é um tipo de classe não-POD (cláusula 9), o construtor padrão para T é chamado (e a inicialização é incorreta se T não tiver construtor padrão acessível);
- se T é um tipo de matriz, cada elemento é inicializado por padrão;
- caso contrário, o objeto será inicializado com zero.

Para inicializar com valor um objeto do tipo T significa:
- se T é um tipo de classe (cláusula 9) com um construtor declarado pelo usuário (12.1), o construtor padrão para T é chamado (e a inicialização é mal formada se T não possui construtor padrão acessível);
- se T é um tipo de classe sem união, sem um construtor declarado pelo usuário, todos os membros de dados não estáticos e componentes da classe base de T são inicializados por valor;
- se T é um tipo de matriz, então cada elemento é inicializado por valor;
- caso contrário, o objeto será inicializado com zero

Um programa que solicita a inicialização padrão ou a inicialização de valor de uma entidade do tipo de referência está incorreto. Se T for um tipo qualificado de cv, a versão não qualificada de cv de T será usada para essas definições de inicialização zero, inicialização padrão e inicialização de valor.

Kirill V. Lyadvinsky
fonte
17
Isso pode estar desatualizado para o C ++ 11. O cppreference.com afirma que a inicialização padrão não inicializa com zero os membros (apenas a inicialização de valor).
Alexei Sholik
3
O @android levanta um ponto importante, que não vejo resposta em outro lugar, por isso fiz uma nova pergunta. stackoverflow.com/questions/22233148/...
Adrian McCarthy