Eu tenho uma estrutura com muitos membros do mesmo tipo, como este
struct VariablePointers {
VariablePtr active;
VariablePtr wasactive;
VariablePtr filename;
};
O problema é que, se eu esquecer de inicializar um dos membros struct (por exemplo wasactive
), assim:
VariablePointers{activePtr, filename}
O compilador não irá reclamar disso, mas terei um objeto parcialmente inicializado. Como posso evitar esse tipo de erro? Eu poderia adicionar um construtor, mas duplicaria a lista de variáveis duas vezes, então eu tenho que digitar tudo isso três vezes!
Adicione também respostas C ++ 11 , se houver uma solução para C ++ 11 (atualmente estou restrito a essa versão). Padrões linguísticos mais recentes também são bem-vindos!
c++
aggregate-initialization
Johannes Schaub - litb
fonte
fonte
-Wmissing-field-initializers
sinalizador de compilação.Respostas:
Aqui está um truque que dispara um erro de vinculador se um inicializador necessário estiver ausente:
Uso:
Resultado:
Ressalvas:
Foo
seja agregado.fonte
Foo
é declarado, mesmo que você nunca chame o operador.Para clang e gcc, você pode compilar com
-Werror=missing-field-initializers
isso transforma o aviso em inicializadores de campo ausentes em um erro. godboltEdit: Para MSVC, parece não haver nenhum aviso emitido, mesmo no nível
/Wall
, por isso não acho possível avisar sobre a falta de inicializadores com este compilador. godboltfonte
Não é uma solução elegante e útil, suponho ... mas deve funcionar também com C ++ 11 e fornecer um erro em tempo de compilação (não em tempo de link).
A idéia é adicionar em sua estrutura um membro adicional, na última posição, de um tipo sem inicialização padrão (e que não pode ser inicializado com um valor do tipo
VariablePtr
(ou qualquer que seja o tipo dos valores anteriores)Por exemplo
Dessa forma, você é forçado a adicionar todos os elementos em sua lista de inicialização agregada, incluindo o valor para inicializar explicitamente o último valor (um número inteiro para
sentinel
, no exemplo) ou você recebe um erro "chamada para o construtor excluído da 'barra'".assim
compilar e
não.
Infelizmente também
não compila.
- EDITAR -
Conforme apontado pelo MSalters (obrigado), há um defeito (outro defeito) no meu exemplo original: um
bar
valor pode ser inicializado com umchar
valor (que é convertível emint
), portanto, funciona a seguinte inicializaçãoe isso pode ser altamente confuso.
Para evitar esse problema, adicionei o seguinte construtor de modelo excluído
portanto, a
f4
declaração anterior gera um erro de compilação porque od
valor é interceptado pelo construtor de modelos excluídofonte
foo f;
falha na compilação, mas talvez isso seja mais um recurso do que uma falha nesse truque. Aceitará se não houver uma proposta melhor que essa.enum
e nomearinit_list_end
(ou simplesmentelist_end
) um valor dissoenum
; mas a legibilidade acrescenta muita máquina de escrever; portanto, dado que o valor adicional é o ponto fraco desta resposta, não sei se é uma boa ideia.constexpr static int eol = 0;
no cabeçalho debar
.test{a, b, c, eol}
parece bastante legível para mim.bar::eol
; é quase como passar umenum
valor; mas não acho importante: o núcleo da resposta é "adicione em sua estrutura um membro adicional, na última posição, de um tipo sem inicialização padrão"; abar
parte é apenas um exemplo trivial para mostrar que a solução funciona; o exato "tipo sem inicialização padrão" deve depender das circunstâncias (IMHO).Para o CppCoreCheck, existe uma regra para verificar exatamente isso, se todos os membros foram inicializados e isso pode ser transformado de aviso em erro - isso geralmente é geral em todo o programa.
Atualizar:
A regra que você deseja verificar faz parte da segurança de tipo
Type.6
:fonte
A maneira mais simples é não fornecer ao tipo dos membros um construtor no-arg:
Outra opção: se seus membros são const &, você precisa inicializar todos eles:
Se você pode viver com um const & member fictício, você pode combinar isso com a ideia de sentinela do @ max66.
De cppreference https://en.cppreference.com/w/cpp/language/aggregate_initialization
Outra opção é pegar a ideia sentinela do max66 e adicionar um pouco de açúcar sintático para facilitar a leitura
fonte
A
inabalável e altera a cópia-semântica (A
não é mais um agregado de valores, por assim dizer) :(1,2,3
objetos são efetivamente locais no armazenamento automático que ficam fora do escopo quando a função termina. E cria o tamanho de (A) 24 em vez de 3 em um sistema com ponteiros de 64 bits (como x86-64).