Inicialização de valor: inicialização padrão ou inicialização zero?

Eu tenho modelogray_code classe que se destina a armazenar um número inteiro não assinado cujos bits subjacentes são armazenados na ordem do código Gray. Aqui está:

template<typename UnsignedInt>
struct gray_code
{
    static_assert(std::is_unsigned<UnsignedInt>::value,
                  "gray code only supports built-in unsigned integers");

    // Variable containing the gray code
    UnsignedInt value;

    // Default constructor
    constexpr gray_code()
        = default;

    // Construction from UnsignedInt
    constexpr explicit gray_code(UnsignedInt value):
        value( (value >> 1) ^ value )
    {}

    // Other methods...
};

Em algum algoritmo genérico, escrevi algo como isto:

template<typename UnsignedInt>
void foo( /* ... */ )
{
    gray_code<UnsignedInt> bar{};
    // Other stuff...
}

Nesse pedaço de código, eu esperavabar ser zero inicializado e, portanto,bar.value ser inicializado com zero. No entanto, depois de ter lutado com erros inesperados, parece quebar.value é inicializado com lixo (4606858 para ser exato) em vez de0u. Isso me surpreendeu, então fui ao cppreference.com para ver o que exatamente a linha acima deveria fazer ...

Pelo que posso ler, o formulárioT object{}; corresponde ainicialização de valor. Achei esta citação interessante:

Em todos os casos, se o par de chaves vazio {} for usado e T for um tipo agregado, a inicialização agregada será executada em vez da inicialização por valor.

Contudo,gray_code possui um construtor fornecido pelo usuário. Portanto, não é um agregado, portanto,inicialização agregada não é realizado.gray_code não tem construtor tomando umastd::initializer_list tãoinicialização de lista também não é realizado. O valor inicializado degray_code deve seguir as regras usuais do C ++ 14 de inicialização de valor:

1) Se T for um tipo de classe sem construtor padrão ou com um construtor padrão fornecido pelo usuário ou com um construtor padrão excluído, o objeto será inicializado por padrão.

2) Se T é um tipo de classe sem um construtor padrão excluído ou fornecido pelo usuário (ou seja, pode ser uma classe com um construtor padrão padrão ou com um definido implicitamente), então o objeto é inicializado com zero e então é inicializado por padrão se tiver um construtor padrão não trivial.

3) Se T é um tipo de matriz, cada elemento da matriz é inicializado por valor.

4) Caso contrário, o objeto será inicializado com zero.

Se eu leio corretamente,gray_code possui um construtor padrão explicitamente padrão (não fornecido pelo usuário), portanto 1) não se aplica. Ele possui um construtor padrão, portanto 2) se aplica:gray_code éinicializado com zero. O construtor padrão padrão parece atender a todos os requisitos de um construtor padrão trivial, portanto, a inicialização padrão não deve ocorrer. Vamos dar uma olhada então em comogray_code é inicializado com zero:

Se T é um tipo escalar, o valor inicial do objeto é a constante zero integral convertida implicitamente em T.

Se T for um tipo de classe sem união, todas as classes base e membros de dados não estáticos serão inicializados com zero e todo o preenchimento será inicializado com zero bits. Os construtores, se houver, são ignorados.

Se T é um tipo de união, o primeiro membro de dados nomeado não estático é inicializado com zero e todo o preenchimento é inicializado com zero bits.

Se T é do tipo matriz, cada elemento é inicializado com zero

Se T for do tipo referência, nada será feito.

gray_code é um tipo de classe sem união. Portanto, todos os seus membros de dados não estáticos devem ser inicializados, o que significa quevalue é inicializado com zero.value satisfazstd::is_unsigned e é, portanto, um tipo escalar, o que significa que deve ser inicializado com "a constante zero integral convertida implicitamente em T".

Então, se eu li corretamente tudo isso, na funçãofoo acima,bar.value deve sempre ser inicializado com0 e nunca deve ser inicializado com lixo, estou certo?

Nota: o compilador com o qual compilei meu código é o MinGW_w4 GCC 4.9.1 com (threads POSIX e exceções de anões), caso isso ajude. Embora às vezes recebo lixo no meu computador, nunca consegui nada além de zero com os compiladores online.

Atualizar: Pareceser um bug do GCC que o erro é meu e não o do meu compilador. Na verdade, ao escrever esta pergunta, assumi, por uma questão de simplicidade, que

class foo {
    foo() = default;
};

e

class foo {
    foo();
};

foo::foo() = default;

eram equivalentes. Eles não são. Aqui está a citação do padrão C ++ 14, seção [dcl.fct.def.default]:

Uma função éfornecido pelo usuário se for declarado pelo usuário e não estiver explicitamente padronizado ou excluído em sua primeira declaração.

Em outras palavras, quando obtive valores de lixo, meu construtor padrão padrão era realmente fornecido pelo usuário, pois não era explicitamente efaultado em sua primeira declaração. Portanto, o que aconteceu não foi a inicialização zero, mas a inicialização padrão. Obrigado @Columbo novamente por apontar o problema real.

questionAnswers(1)

yourAnswerToTheQuestion