Est-il possible d'initialiser des structures en C ++ comme indiqué ci-dessous
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Les liens ici et ici mentionnent qu'il est possible d'utiliser ce style uniquement en C. Si oui, pourquoi cela n'est-il pas possible en C ++? Y a-t-il une raison technique sous-jacente pour laquelle il n'est pas implémenté en C ++, ou est-ce une mauvaise pratique d'utiliser ce style. J'aime utiliser cette façon d'initialiser car ma structure est grande et ce style me donne une lisibilité claire de quelle valeur est affectée à quel membre.
Veuillez partager avec moi s'il existe d'autres moyens par lesquels nous pouvons atteindre la même lisibilité.
J'ai référé les liens suivants avant de poster cette question
Réponses:
Si vous souhaitez clarifier la valeur de chaque initialiseur, divisez-la simplement sur plusieurs lignes, avec un commentaire sur chacune:
la source
char*
) que l'un des autres membres au-dessus ou en dessous de la structure, car il n'y a aucun risque de les échanger.(struct timeval){ .seconds = 0, .microseconds = 100 }
sera toujours d'une centaine de microsecondes, maistimeval { 0, 100 }
pourrait être d'une centaine de SECONDES . Vous ne voulez pas trouver quelque chose comme ça à la dure.Après que ma question n'ait abouti à aucun résultat satisfaisant (car C ++ n'implémente pas d'init basé sur les balises pour les structures), j'ai pris l'astuce que j'ai trouvée ici: les membres d'une structure C ++ sont-ils initialisés à 0 par défaut?
Pour vous, cela reviendrait à le faire:
C'est certainement le plus proche de ce que vous vouliez à l'origine (zéro tous les champs sauf ceux que vous souhaitez initialiser).
la source
static address temp_address = {};
marchera. Le remplir ensuite dépend de l'exécution, oui. Vous pouvez contourner cela en fournissant une fonction statique qui ne init pour vous:static address temp_address = init_my_temp_address();
.init_my_temp_address
peut être une fonction lambda:static address temp_address = [] () { /* initialization code */ }();
address
et vous ne saurez jamais tous les endroits qui créent unaddress
et maintenant n'initialisez pas votre nouveau membre.Comme d'autres l'ont mentionné, il s'agit d'un initialiseur désigné.
Cette fonctionnalité fait partie de C ++ 20
la source
Les identifiants de champ sont en effet la syntaxe d'initialisation C. En C ++, donnez simplement les valeurs dans le bon ordre sans les noms de champs. Malheureusement, cela signifie que vous devez tous les donner (en fait, vous pouvez omettre les champs à valeur nulle de fin et le résultat sera le même):
la source
Cette fonction est appelée initialiseurs désignés . Il s'agit d'un ajout à la norme C99. Cependant, cette fonctionnalité a été omise du C ++ 11. Selon le langage de programmation C ++, 4e édition, section 44.3.3.2 (Fonctionnalités C non adoptées par C ++):
La grammaire C99 a les initialiseurs désignés [Voir ISO / IEC 9899: 2011, Projet de comité N1570 - 12 avril 2011]
6.7.9 Initialisation
D'un autre côté, le C ++ 11 n'a pas les initialiseurs désignés [Voir ISO / IEC 14882: 2011, Projet de comité N3690 - 15 mai 2013]
8.5 Initialiseurs
Pour obtenir le même effet, utilisez des constructeurs ou des listes d'initialisation:
la source
Vous pouvez simplement initialiser via ctor:
la source
struct address
. De plus, les types POD n'ont souvent intentionnellement ni constructeur ni destructeur.Vous pouvez même regrouper la solution de Gui13 dans une seule déclaration d'initialisation:
Avertissement: je ne recommande pas ce style
la source
address
et le code compilera toujours avec un million de places en initialisant uniquement les cinq membres d'origine. La meilleure partie de l'initialisation de la structure est que vous pouvez avoir tous les membresconst
et cela vous forcera à tous les initialiserJe sais que cette question est assez ancienne, mais j'ai trouvé une autre façon d'initialiser, en utilisant constexpr et le curry:
Cette méthode fonctionne également pour les variables statiques globales et même celles constexpr. Le seul inconvénient est la mauvaise maintenabilité: chaque fois qu'un autre membre doit être initialisé à l'aide de cette méthode, toutes les méthodes d'initialisation des membres doivent être modifiées.
la source
Il se peut que je manque quelque chose ici, pourquoi pas:
la source
Il n'est pas implémenté en C ++. (aussi, des
char*
cordes? J'espère que non).Habituellement, si vous avez autant de paramètres, c'est une odeur de code assez grave. Mais à la place, pourquoi ne pas simplement initialiser la structure par la valeur et ensuite affecter chaque membre?
la source
char*
cordes? J'espère que non)." - Eh bien, c'est un exemple C.char*
mais le typeconst char*
est beaucoup plus sûr et tout le monde utilise simplementstd::string
parce qu'il est beaucoup plus fiable.J'ai trouvé cette façon de le faire pour les variables globales, qui ne nécessite pas de modifier la définition de la structure d'origine:
puis déclarez la variable d'un nouveau type hérité du type struct d'origine et utilisez le constructeur pour l'initialisation des champs:
Pas aussi élégant que le style C ...
Pour une variable locale, elle nécessite un memset supplémentaire (this, 0, sizeof (* this)) au début du constructeur, donc ce n'est clairement pas pire et la réponse de @ gui13 est plus appropriée.
(Notez que 'temp_address' est une variable de type 'temp_address', cependant ce nouveau type hérite de 'address' et peut être utilisé partout où 'address' est attendu, donc c'est OK.)
la source
J'ai rencontré un problème similaire aujourd'hui, où j'ai une structure que je veux remplir avec des données de test qui seront passées comme arguments à une fonction que je teste. Je voulais avoir un vecteur de ces structures et recherchais une méthode à une ligne pour initialiser chaque structure.
J'ai fini par utiliser une fonction constructeur dans la structure, qui, je crois, a également été suggérée dans quelques réponses à votre question.
C'est probablement une mauvaise pratique que les arguments du constructeur portent les mêmes noms que les variables de membre public, ce qui nécessite l'utilisation du
this
pointeur. Quelqu'un peut suggérer une modification s'il existe une meilleure méthode.Dans lequel j'ai utilisé dans ma fonction de test pour appeler la fonction en cours de test avec divers arguments comme celui-ci:
la source
C'est possible, mais seulement si la structure que vous initialisez est une structure POD (plain old data). Il ne peut contenir aucune méthode, constructeur ou même valeur par défaut.
la source
En C ++, les initialiseurs de style C ont été remplacés par des constructeurs qui, au moment de la compilation, peuvent garantir que seules les initialisations valides sont effectuées (c'est-à-dire qu'après l'initialisation, les membres de l'objet sont cohérents).
C'est une bonne pratique, mais parfois une pré-initialisation est pratique, comme dans votre exemple. La POO résout ce problème par des classes abstraites ou des modèles de conception créatifs .
À mon avis, l'utilisation de cette méthode sécurisée tue la simplicité et parfois le compromis de sécurité peut être trop cher, car un code simple n'a pas besoin d'une conception sophistiquée pour rester maintenable.
Comme solution alternative, je suggère de définir des macros en utilisant des lambdas pour simplifier l'initialisation pour ressembler presque au style C:
La macro ADDRESS se développe pour
qui crée et appelle le lambda. Les paramètres de macro sont également séparés par des virgules, vous devez donc mettre l'initialiseur entre crochets et appeler comme
Vous pouvez également écrire un initialiseur de macro généralisé
mais alors l'appel est un peu moins beau
cependant, vous pouvez définir la macro ADRESSE à l'aide de la macro générale INIT facilement
la source
Dans GNUC ++ (semble obsolète depuis la 2.5, il y a longtemps :) Voir les réponses ici: initialisation de la structure C à l'aide d'étiquettes. Ça marche, mais comment? ), il est possible d'initialiser une structure comme celle-ci:
la source
Inspiré par cette réponse vraiment soignée: ( https://stackoverflow.com/a/49572324/4808079 )
Vous pouvez faire des fermetures de lamba:
.
Ou, si vous voulez être très chic
Il y a quelques inconvénients à cela, principalement liés aux membres non initialisés. D'après les commentaires des réponses liées, il se compile efficacement, même si je ne l'ai pas testé.
Dans l'ensemble, je pense simplement que c'est une approche soignée.
la source