Ist es möglich, Strukturen in C ++ wie unten angegeben zu initialisieren?
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
In den Links hier und hier wird erwähnt, dass dieser Stil nur in C verwendet werden kann. Wenn ja, warum ist dies in C ++ nicht möglich? Gibt es einen technischen Grund, warum es nicht in C ++ implementiert ist, oder ist es eine schlechte Praxis, diesen Stil zu verwenden. Ich verwende diese Art der Initialisierung gerne, weil meine Struktur groß ist und dieser Stil mir eine klare Lesbarkeit darüber gibt, welcher Wert welchem Mitglied zugewiesen ist.
Bitte teilen Sie mir mit, ob es andere Möglichkeiten gibt, mit denen wir die gleiche Lesbarkeit erreichen können.
Ich habe die folgenden Links verwiesen, bevor ich diese Frage gestellt habe
Antworten:
Wenn Sie klarstellen möchten, was jeder Initialisierungswert ist, teilen Sie ihn einfach in mehrere Zeilen mit einem Kommentar zu jeder Zeile auf:
quelle
char*
) wie eines der anderen Elemente über oder unter der Struktur hinzufügen , da kein Risiko besteht, sie auszutauschen.(struct timeval){ .seconds = 0, .microseconds = 100 }
wird immer hundert Mikrosekunden sein,timeval { 0, 100 }
könnte aber hundert Sekunden sein . Sie wollen so etwas nicht auf die harte Tour herausfinden.Nachdem meine Frage zu keinem zufriedenstellenden Ergebnis geführt hat (da C ++ kein tagbasiertes Init für Strukturen implementiert), habe ich den hier gefundenen Trick ausgeführt: Werden Mitglieder einer C ++ - Struktur standardmäßig auf 0 initialisiert?
Für Sie wäre es das:
Dies ist sicherlich das, was Sie ursprünglich am nächsten wollten (null aller Felder außer denen, die Sie initialisieren möchten).
quelle
static address temp_address = {};
wird funktionieren. Das anschließende Auffüllen hängt von der Laufzeit ab, ja. Sie können dies umgehen, indem Sie eine statische Funktion bereitstellen, die den Init für Sie ausführt :static address temp_address = init_my_temp_address();
.init_my_temp_address
kann eine Lambda-Funktion sein:static address temp_address = [] () { /* initialization code */ }();
address
Sie nie alle Orte kennen , an denen ein Mitglied erstellt wird, undaddress
Ihr neues Mitglied jetzt nicht initialisieren.Wie andere bereits erwähnt haben, wird dies als Initialisierer bezeichnet.
Diese Funktion ist Teil von C ++ 20
quelle
Die Feldbezeichner sind in der Tat C-Initialisierersyntax. In C ++ geben Sie einfach die Werte in der richtigen Reihenfolge ohne die Feldnamen an. Leider bedeutet dies, dass Sie alle angeben müssen (tatsächlich können Sie nachfolgende Felder mit dem Wert Null weglassen, und das Ergebnis ist das gleiche):
quelle
Diese Funktion wird als designierte Initialisierer bezeichnet . Es ist eine Ergänzung zum C99-Standard. Diese Funktion wurde jedoch in C ++ 11 nicht berücksichtigt. Gemäß der Programmiersprache C ++, 4. Ausgabe, Abschnitt 44.3.3.2 (C-Funktionen, die von C ++ nicht übernommen wurden):
Die C99-Grammatik hat die festgelegten Initialisierer [Siehe ISO / IEC 9899: 2011, N1570 Committee Draft - 12. April 2011]
6.7.9 Initialisierung
Andererseits verfügt das C ++ 11 nicht über die vorgesehenen Initialisierer [Siehe ISO / IEC 14882: 2011, N3690 Committee Draft - 15. Mai 2013]
8.5 Initialisierer
Verwenden Sie Konstruktoren oder Initialisiererlisten, um den gleichen Effekt zu erzielen:
quelle
Sie können einfach über ctor initialisieren:
quelle
struct address
. Außerdem haben POD-Typen häufig absichtlich keinen Konstruktor und Destruktor.Sie können die Gui13-Lösung sogar in eine einzelne Initialisierungsanweisung packen:
Haftungsausschluss: Ich empfehle diesen Stil nicht
quelle
address
und der Code weiterhin mit einer Million Stellen kompiliert wird, wobei nur die ursprünglichen fünf Mitglieder initialisiert werden. Der beste Teil der Strukturinitialisierung ist, dass Sie alle Mitglieder haben könnenconst
und es Sie zwingen wird, sie alle zu initialisierenIch weiß, dass diese Frage ziemlich alt ist, aber ich habe einen anderen Weg gefunden, sie mit constexpr und curry zu initialisieren:
Diese Methode funktioniert auch für globale statische Variablen und sogar für constexpr-Variablen. Der einzige Nachteil ist die schlechte Wartbarkeit: Jedes Mal, wenn ein anderes Mitglied mit dieser Methode initialisierbar gemacht werden muss, müssen alle Initialisierungsmethoden für Mitglieder geändert werden.
quelle
Ich könnte hier etwas vermissen, warum nicht:
quelle
Es ist nicht in C ++ implementiert. (ebenfalls,
char*
Saiten? Ich hoffe nicht).Wenn Sie so viele Parameter haben, ist dies normalerweise ein ziemlich schwerwiegender Codegeruch. Aber warum nicht einfach die Struktur wertinitialisieren und dann jedem Mitglied zuweisen?
quelle
char*
Saiten? Ich hoffe nicht)." - Nun, es ist ein C-Beispiel.char*
aber esconst char*
ist viel typsicherer und jeder verwendetstd::string
es nur, weil es viel zuverlässiger ist.Ich habe diese Methode für globale Variablen gefunden, bei der die ursprüngliche Strukturdefinition nicht geändert werden muss:
Deklarieren Sie dann die Variable eines neuen Typs, der vom ursprünglichen Strukturtyp geerbt wurde, und verwenden Sie den Konstruktor für die Feldinitialisierung:
Nicht ganz so elegant wie der C-Stil ...
Für eine lokale Variable ist ein zusätzliches Memset (this, 0, sizeof (* this)) am Anfang des Konstruktors erforderlich, daher ist es eindeutig nicht schlechter und die Antwort von @ gui13 ist angemessener.
(Beachten Sie, dass 'temp_address' eine Variable vom Typ 'temp_address' ist. Dieser neue Typ erbt jedoch von 'address' und kann an jedem Ort verwendet werden, an dem 'address' erwartet wird. Daher ist dies in Ordnung.)
quelle
Ich hatte heute ein ähnliches Problem, bei dem ich eine Struktur habe, die ich mit Testdaten füllen möchte, die als Argumente an eine Funktion übergeben werden, die ich teste. Ich wollte einen Vektor dieser Strukturen haben und suchte nach einer Einzeiler-Methode, um jede Struktur zu initialisieren.
Am Ende hatte ich eine Konstruktorfunktion in der Struktur, die meiner Meinung nach auch in einigen Antworten auf Ihre Frage vorgeschlagen wurde.
Es ist wahrscheinlich eine schlechte Praxis, wenn die Argumente an den Konstruktor dieselben Namen wie die öffentlichen Mitgliedsvariablen haben, was die Verwendung des
this
Zeigers erfordert . Jemand kann eine Bearbeitung vorschlagen, wenn es einen besseren Weg gibt.Was ich in meiner Testfunktion verwendet habe, um die zu testende Funktion mit verschiedenen Argumenten wie diesem aufzurufen:
quelle
Es ist möglich, aber nur, wenn die Struktur, die Sie initialisieren, eine POD-Struktur (Plain Old Data) ist. Es darf keine Methoden, Konstruktoren oder sogar Standardwerte enthalten.
quelle
In C ++ wurden die Initialisierer im C-Stil durch Konstruktoren ersetzt, die durch die Kompilierungszeit sicherstellen können, dass nur gültige Initialisierungen durchgeführt werden (dh nach der Initialisierung sind die Objektelemente konsistent).
Es ist eine gute Vorgehensweise, aber manchmal ist eine Vorinitialisierung praktisch, wie in Ihrem Beispiel. OOP löst dies durch abstrakte Klassen oder kreative Designmuster .
Meiner Meinung nach macht die Verwendung dieser sicheren Methode die Einfachheit zunichte und manchmal ist der Kompromiss zwischen Sicherheit zu teuer, da einfacher Code kein ausgeklügeltes Design benötigt, um wartbar zu bleiben.
Als alternative Lösung schlage ich vor, Makros mit Lambdas zu definieren, um die Initialisierung so zu vereinfachen, dass sie fast wie im C-Stil aussieht:
Das ADDRESS-Makro wird auf erweitert
das schafft und nennt das Lambda. Makroparameter werden ebenfalls durch Kommas getrennt, sodass Sie den Initialisierer in Klammern setzen und wie aufrufen müssen
Sie können auch einen verallgemeinerten Makroinitialisierer schreiben
aber dann ist der Anruf etwas weniger schön
Sie können das ADDRESS-Makro jedoch einfach mit dem allgemeinen INIT-Makro definieren
quelle
In GNUC ++ (scheint seit 2.5 vor langer Zeit veraltet zu sein :) Siehe die Antworten hier: C-Struktur-Initialisierung mit Labels. Es funktioniert, aber wie? ) ist es möglich, eine Struktur wie folgt zu initialisieren:
quelle
Inspiriert von dieser wirklich tollen Antwort: ( https://stackoverflow.com/a/49572324/4808079 )
Sie können Lamba-Verschlüsse machen:
.
Oder wenn Sie sehr schick sein wollen
Dies hat einige Nachteile, die hauptsächlich mit nicht initialisierten Mitgliedern zu tun haben. Nach den Kommentaren der verknüpften Antworten wird es effizient kompiliert, obwohl ich es nicht getestet habe.
Insgesamt denke ich nur, dass es ein ordentlicher Ansatz ist.
quelle