É possível inicializar estruturas em C ++, como indicado abaixo
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Os links aqui e aqui mencionam que é possível usar esse estilo somente em C. Se sim, por que isso não é possível em C ++? Existe alguma razão técnica subjacente para que ele não seja implementado em C ++ ou é uma má prática usar esse estilo. Eu gosto de usar essa maneira de inicializar porque minha estrutura é grande e esse estilo me dá uma legibilidade clara de qual valor é atribuído a qual membro.
Por favor, compartilhe comigo se houver outras maneiras pelas quais possamos obter a mesma legibilidade.
Consultei os seguintes links antes de postar esta pergunta
Respostas:
Se você quiser deixar claro qual é o valor de cada inicializador, apenas divida-o em várias linhas, com um comentário em cada um:
fonte
char*
) de um dos outros membros acima ou abaixo na estrutura, porque não há risco de trocá-los.(struct timeval){ .seconds = 0, .microseconds = 100 }
sempre será cem microssegundos, mastimeval { 0, 100 }
pode ser cem SEGUNDOS . Você não quer encontrar algo assim da maneira mais difícil.Depois que minha pergunta não resultou em um resultado satisfatório (porque o C ++ não implementa init baseado em tags para estruturas), segui o truque que encontrei aqui: Os membros de uma estrutura C ++ são inicializados como 0 por padrão?
Para você, isso equivaleria a:
Este é certamente o mais próximo do que você queria originalmente (zere todos os campos, exceto aqueles que você deseja inicializar).
fonte
static address temp_address = {};
vai funcionar. Preenchê-lo depois depende do tempo de execução, sim. Você pode ignorar isso, fornecendo uma função estática que faz a inicialização para você:static address temp_address = init_my_temp_address();
.init_my_temp_address
pode ser uma função lambda:static address temp_address = [] () { /* initialization code */ }();
address
e você nunca saberá de todos os lugares que criam umaddress
e agora não inicializam seu novo membro.Como outros já mencionaram, isso é designado como inicializador.
Esse recurso faz parte do C ++ 20
fonte
Os identificadores de campo são de fato a sintaxe do inicializador C. Em C ++, basta fornecer os valores na ordem correta, sem os nomes dos campos. Infelizmente, isso significa que você precisa fornecer todos eles (na verdade, você pode omitir os campos com valor zero à direita e o resultado será o mesmo):
fonte
Esse recurso é chamado de inicializadores designados . É uma adição ao padrão C99. No entanto, esse recurso foi deixado de fora do C ++ 11. De acordo com a linguagem de programação C ++, 4ª edição, seção 44.3.3.2 (recursos C não adotados pelo C ++):
A gramática C99 possui os inicializadores designados [Ver ISO / IEC 9899: 2011, N1570 Committee Draft - 12 de abril de 2011]
6.7.9 Inicialização
Por outro lado, o C ++ 11 não possui os inicializadores designados [Ver ISO / IEC 14882: 2011, N3690 Committee Draft - 15 de maio de 2013]
8.5 Inicializadores
Para obter o mesmo efeito, use construtores ou listas de inicializadores:
fonte
Você pode apenas inicializar via ctor:
fonte
struct address
. Além disso, os tipos de POD geralmente não têm intencionalmente construtor e destruidor.Você pode até empacotar a solução do Gui13 em uma única declaração de inicialização:
Isenção de responsabilidade: eu não recomendo este estilo
fonte
address
e o código ainda será compilado com um milhão de lugares, inicializando apenas os cinco membros originais. A melhor parte de inicialização struct é que você pode ter todos os membrosconst
e que irá forçá-lo para inicializar todos elesEu sei que essa pergunta é bastante antiga, mas encontrei outra maneira de inicializar, usando constexpr e currying:
Este método também funciona para variáveis estáticas globais e até mesmo para as que são comuns. A única desvantagem é a má manutenção: sempre que outro membro precisar ser inicializado usando esse método, todos os métodos de inicialização de membros deverão ser alterados.
fonte
Eu posso estar perdendo alguma coisa aqui, por que não:
fonte
Não é implementado em C ++. (também,
char*
cordas? Espero que não).Geralmente, se você tem tantos parâmetros, é um cheiro de código bastante sério. Mas, em vez disso, por que não simplesmente inicializar com valor a estrutura e depois atribuir cada membro?
fonte
char*
cordas? Espero que não)." Bem, é um exemplo em C.char*
masconst char*
é muito mais seguro para o tipo e todo mundo usa,std::string
porque é muito mais confiável.Eu encontrei essa maneira de fazer isso para variáveis globais, que não precisam modificar a definição da estrutura original:
declare a variável de um novo tipo herdada do tipo de estrutura original e use o construtor para a inicialização dos campos:
Não é tão elegante quanto o estilo C ...
Para uma variável local, é necessário um conjunto memset adicional (this, 0, sizeof (* this)) no início do construtor, portanto, claramente não é pior e a resposta de @ gui13 é mais apropriada.
(Observe que 'temp_address' é uma variável do tipo 'temp_address'; no entanto, esse novo tipo é herdado de 'address' e pode ser usado em todos os locais em que 'address' é esperado, portanto, está OK.)
fonte
Hoje enfrentei um problema semelhante, onde tenho uma estrutura que quero preencher com dados de teste que serão passados como argumentos para uma função que estou testando. Eu queria ter um vetor dessas estruturas e estava procurando um método de uma linha para inicializar cada estrutura.
Acabei indo com uma função construtora na estrutura, que acredito que também foi sugerida em algumas respostas à sua pergunta.
Provavelmente, é uma má prática ter os argumentos para o construtor com os mesmos nomes que as variáveis públicas do membro, exigindo o uso do
this
ponteiro. Alguém pode sugerir uma edição, se houver uma maneira melhor.Que eu usei na minha função de teste para chamar a função sendo testada com vários argumentos como este:
fonte
É possível, mas apenas se a estrutura que você está inicializando for uma estrutura POD (dados antigos simples). Ele não pode conter nenhum método, construtor ou mesmo valor padrão.
fonte
No C ++, os inicializadores do estilo C foram substituídos por construtores que, durante o tempo de compilação, podem garantir que apenas as inicializações válidas sejam realizadas (ou seja, após a inicialização, os membros do objeto são consistentes).
É uma boa prática, mas às vezes uma pré-inicialização é útil, como no seu exemplo. OOP resolve isso por classes abstratas ou padrões de design criacionais .
Na minha opinião, o uso dessa maneira segura reduz a simplicidade e, às vezes, a troca de segurança pode ser muito cara, pois o código simples não precisa de design sofisticado para manter a manutenção.
Como solução alternativa, sugiro definir macros usando lambdas para simplificar a inicialização para se parecer quase com o estilo C:
A macro ADDRESS se expande para
que cria e chama o lambda. Os parâmetros de macro também são separados por vírgula; portanto, você precisa colocar o inicializador entre colchetes e chamar como
Você também pode escrever inicializador de macro generalizado
mas a chamada é um pouco menos bonita
no entanto, você pode definir a macro ADDRESS usando a macro INIT geral facilmente
fonte
No GNUC ++ (parece obsoleto desde a versão 2.5, há muito tempo :) :) Veja as respostas aqui: Inicialização C struct usando rótulos. Funciona, mas como? ), é possível inicializar uma estrutura como esta:
fonte
Inspirado por esta resposta realmente elegante: ( https://stackoverflow.com/a/49572324/4808079 )
Você pode fazer fechamentos de lamba:
.
Ou, se você quiser ser muito chique
Existem algumas desvantagens envolvidas, principalmente relacionadas a membros não inicializados. Pelo que dizem os comentários das respostas vinculadas, ele é compilado com eficiência, embora eu não o tenha testado.
No geral, acho que é uma abordagem interessante.
fonte