MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Pourquoi?
Je n'ai pas pu trouver de réponse sur SO, alors laissez-moi répondre à ma propre question.
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Pourquoi?
Je n'ai pas pu trouver de réponse sur SO, alors laissez-moi répondre à ma propre question.
auto
?std::map<std::string, std::vector<std::string>>::const_iterator
voudrait un mot avec vous.using MyContainer = std::map<std::string, std::vector<std::string>>;
c'est encore mieux (d'autant plus que vous pouvez le modéliser!)Réponses:
Fondamentalement, copier et coller à partir de "The C ++ Programming Language 4th Edition" de Bjarne Stroustrup :
L'initialisation de liste ne permet pas de rétrécissement (§iso.8.5.4). C'est:
Exemple:
La seule situation où = est préféré à {} consiste à utiliser un
auto
mot-clé pour obtenir le type déterminé par l'initialiseur.Exemple:
Conclusion
Préférez l'initialisation {} aux alternatives, sauf si vous avez une bonne raison de ne pas le faire.
la source
()
peut être analysée comme une déclaration de fonction. C'est déroutant et incohérent que vous puissiez direT t(x,y,z);
mais pasT t()
. Et parfois, vous êtes certainx
, vous ne pouvez même pas le direT t(x);
.std::initializer_list
. RedXIII mentionne ce problème (et le balaye simplement), tandis que vous l'ignorez complètement.A(5,4)
etA{5,4}
peut appeler des fonctions complètement différentes, et c'est une chose importante à savoir. Cela peut même entraîner des appels qui ne semblent pas intuitifs. Dire que vous devriez préférer{}
par défaut amènera les gens à mal comprendre ce qui se passe. Ce n'est pas de ta faute, cependant. Personnellement, je pense que c'est une fonctionnalité extrêmement mal pensée.auto var{ 5 }
et il ne sera pas déduitint
plus questd::initializer_list<int>
.Il existe déjà d'excellentes réponses concernant les avantages de l'initialisation de liste, mais ma règle de base personnelle n'est PAS d'utiliser des accolades chaque fois que possible, mais de la rendre dépendante de la signification conceptuelle:
D'une part, de cette façon, je suis toujours sûr que l'objet est initialisé, qu'il s'agisse par exemple d'une "vraie" classe avec un constructeur par défaut qui serait appelé de toute façon ou d'un type intégré / POD. Deuxièmement, il est - dans la plupart des cas - conforme à la première règle, car un objet initialisé par défaut représente souvent un objet "vide".
D'après mon expérience, cet ensemble de règles peut être appliqué de manière beaucoup plus cohérente que l'utilisation d'accolades par défaut, mais avoir à se souvenir explicitement de toutes les exceptions lorsqu'elles ne peuvent pas être utilisées ou ont une signification différente de la syntaxe "normale" d'appel de fonction avec parenthèses (appelle une surcharge différente).
Il s'intègre par exemple parfaitement avec les types de bibliothèques standard comme
std::vector
:la source
const int &b{}
<- n'essaie pas de créer une référence non initialisée, mais la lie à un objet entier temporaire. Deuxième exemple:struct A { const int &b; A():b{} {} };
<- n'essaie pas de créer une référence non initialisée (comme le()
ferait), mais la lie à un objet entier temporaire, puis le laisse pendant. GCC même avec-Wall
ne met pas en garde pour le deuxième exemple.Il y a BEAUCOUP de raisons d'utiliser l'initialisation de l'accolade, mais vous devez savoir que le
initializer_list<>
constructeur est préféré aux autres constructeurs , l'exception étant le constructeur par défaut. Cela entraîne des problèmes avec les constructeurs et les modèles où leT
constructeur de type peut être soit une liste d'initialisation, soit un ancien ctor simple.En supposant que vous ne rencontriez pas de telles classes, il y a peu de raisons de ne pas utiliser la liste des initialiseurs.
la source
{ ... }
) sauf si vous voulez lainitializer_list
sémantique (enfin, et peut-être pour la construction par défaut d'un objet).std::initializer_list
règle existe même - elle ajoute simplement de la confusion et du désordre à la langue. Qu'est-ce qui ne va pasFoo{{a}}
si vous voulez lestd::initializer_list
constructeur? Cela semble tellement plus facile à comprendre que d'avoir lastd::initializer_list
priorité sur toutes les autres surcharges.Foo{{a}}
suit une logique pour moi bien plus que celleFoo{a}
qui se transforme en priorité de liste d'initialisation (les utilisateurs pourraient penser que hm ...)std::initializer_list<Foo>
constructeur, mais qu'il va être ajouté à laFoo
classe à un moment donné pour étendre son interface? Ensuite, les utilisateurs deFoo
classe sont foutus.initializer_list<>
), qu'elle ne qualifie pas vraiment qui dit qu'elle est préférée, puis continue de mentionner un bon cas où elle n'est PAS préférée. Que manque-t-il que ~ 30 autres personnes (au 21/04/2016) ont trouvé utile?C'est plus sûr aussi longtemps que vous ne construisez pas avec -Wno-restricting comme disons Google dans Chromium. Si vous le faites, alors c'est MOINS sûr. Sans cet indicateur, les seuls cas dangereux seront corrigés par C ++ 20.
Remarque: A) Les accolades sont plus sûres car elles ne permettent pas de rétrécissement. B) Les accolades sont moins sûres car elles peuvent contourner les constructeurs privés ou supprimés, et appeler implicitement les constructeurs marqués explicitement.
Ces deux combinés signifient qu'ils sont plus sûrs si ce qui est à l'intérieur sont des constantes primitives, mais moins sûrs si ce sont des objets (bien qu'ils soient fixes en C ++ 20)
la source