MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Warum?
Ich konnte auf SO keine Antwort finden, also lass mich meine eigene Frage beantworten.
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Warum?
Ich konnte auf SO keine Antwort finden, also lass mich meine eigene Frage beantworten.
auto
?std::map<std::string, std::vector<std::string>>::const_iterator
möchte ein Wort mit dir.using MyContainer = std::map<std::string, std::vector<std::string>>;
ist noch besser (vor allem, wie Sie es Vorlage können!)Antworten:
Grundsätzlich kopieren und einfügen aus Bjarne Stroustrups "The C ++ Programming Language 4th Edition" :
Die Listeninitialisierung erlaubt keine Verengung (§iso.8.5.4). Das ist:
Beispiel:
Die einzige Situation, in der = gegenüber {} bevorzugt wird, ist die Verwendung
auto
Schlüsselworts, um den vom Initialisierer bestimmten Typ abzurufen.Beispiel:
Fazit
Ziehen Sie die {} Initialisierung Alternativen vor, es sei denn, Sie haben einen starken Grund, dies nicht zu tun.
quelle
()
als Funktionsdeklaration analysiert werden kann. Es ist verwirrend und inkonsistent, dass man sagen kann,T t(x,y,z);
aber nichtT t()
. Und manchmal, Sie sicherx
, können Sie nicht einmal sagenT t(x);
.std::initializer_list
. RedXIII erwähnt dieses Problem (und wischt es einfach ab), während Sie es vollständig ignorieren.A(5,4)
undA{5,4}
kann ganz andere Funktionen aufrufen, und dies ist eine wichtige Sache zu wissen. Es kann sogar zu Anrufen führen, die nicht intuitiv erscheinen. Wenn Sie sagen, dass Sie{}
standardmäßig bevorzugen sollten, werden die Leute falsch verstehen, was los ist. Dies ist jedoch nicht deine Schuld. Ich persönlich denke, es ist eine äußerst schlecht durchdachte Funktion.auto var{ 5 }
und es wirdint
nicht mehr als abgeleitetstd::initializer_list<int>
.Es gibt bereits gute Antworten auf die Vorteile der Listeninitialisierung. Meine persönliche Faustregel lautet jedoch, nach Möglichkeit KEINE geschweiften Klammern zu verwenden, sondern diese von der konzeptionellen Bedeutung abhängig zu machen:
Zum einen bin ich mir auf diese Weise immer sicher, dass das Objekt initialisiert wird, unabhängig davon, ob es sich beispielsweise um eine "echte" Klasse mit einem Standardkonstruktor handelt, der trotzdem aufgerufen wird, oder um einen eingebauten / POD-Typ. Zweitens stimmt es - in den meisten Fällen - mit der ersten Regel überein, da ein standardmäßig initialisiertes Objekt häufig ein "leeres" Objekt darstellt.
Nach meiner Erfahrung kann dieser Regelsatz viel konsistenter angewendet werden als die Verwendung von geschweiften Klammern, muss jedoch alle Ausnahmen explizit berücksichtigen, wenn sie nicht verwendet werden können oder eine andere Bedeutung haben als die "normale" Funktionsaufrufsyntax in Klammern (ruft eine andere Überlastung auf).
Es passt zB gut zu Standardbibliothekstypen wie
std::vector
:quelle
const int &b{}
<- versucht nicht, eine nicht initialisierte Referenz zu erstellen, sondern bindet sie an ein temporäres ganzzahliges Objekt. Zweites Beispiel:struct A { const int &b; A():b{} {} };
<- versucht nicht (wie üblich()
), eine nicht initialisierte Referenz zu erstellen , sondern bindet sie an ein temporäres ganzzahliges Objekt und lässt sie dann baumeln. GCC-Wall
warnt auch mit nicht für das zweite Beispiel.Es gibt VIELE Gründe, die Klammerinitialisierung zu verwenden, aber Sie sollten sich bewusst sein, dass der
initializer_list<>
Konstruktor den anderen Konstruktoren vorgezogen wird , mit Ausnahme des Standardkonstruktors. Dies führt zu Problemen mit Konstruktoren und Vorlagen, bei denen derT
Typkonstruktor entweder eine Initialisierungsliste oder ein einfacher alter Ctor sein kann.Angenommen, Sie stoßen nicht auf solche Klassen, gibt es wenig Grund, die Intializer-Liste nicht zu verwenden.
quelle
{ ... }
), es sei denn, Sie möchten dieinitializer_list
Semantik (naja, und vielleicht zum Standardkonstruieren eines Objekts).std::initializer_list
Regel überhaupt existiert - sie bringt nur Verwirrung und Chaos in die Sprache. Was ist falsch daran,Foo{{a}}
wenn Sie denstd::initializer_list
Konstruktor wollen ? Das scheint so viel einfacher zu verstehen, alsstd::initializer_list
Vorrang vor allen anderen Überlastungen zu haben.Foo{{a}}
folgt einer Logik für mich weit mehr als die,Foo{a}
die sich in die Priorität der Intializer-Liste verwandelt (Ups könnten der Benutzer denken, hm ...)std::initializer_list<Foo>
Konstruktor, aber es wird zu hinzugefügt , um dieFoo
an einem bestimmten Punkt Klasse seine Schnittstelle zu verlängern? Dann sind Benutzer derFoo
Klasse vermasselt.initializer_list<>
) auf, den es nicht wirklich qualifiziert, wer sagt , dass es bevorzugt wird, und erwähnt dann einen guten Fall, in dem es NICHT bevorzugt wird. Was vermisse ich, dass ~ 30 andere Personen (Stand 21.04.2016) hilfreich fanden?Es ist nur sicherer, solange Sie nicht mit -Wno-Engeing bauen, wie es Google in Chromium tut. Wenn Sie dies tun, ist es WENIGER sicher. Ohne dieses Flag werden die einzigen unsicheren Fälle jedoch von C ++ 20 behoben.
Hinweis: A) Geschweifte Klammern sind sicherer, da sie keine Verengung zulassen. B) Curly-Bracker sind weniger sicher, da sie private oder gelöschte Konstruktoren umgehen und explizit markierte Konstruktoren implizit aufrufen können.
Diese beiden kombinierten Mittel bedeuten, dass sie sicherer sind, wenn es sich um primitive Konstanten handelt, aber weniger sicher, wenn es sich um Objekte handelt (obwohl in C ++ 20 festgelegt).
quelle