MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Pourquoi?
Je ne pouvais pas trouver de réponse sur SO, alors laissez-moi répondre à ma propre question.
Copier et coller à partir de Bjarne Stroustrup "La 4ème édition du langage de programmation C++" :
L'initialisation de la liste ne permet pas le rétrécissement (§iso.8.5.4). C'est:
Exemple:
void fun(double val, int val2) {
int x2 = val; // if val==7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2==1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
La situation seulement où = est préféré à {} est lorsqu’on utilise le mot clé auto
pour obtenir le type déterminé par l’initialiseur.
Exemple:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
Préférez {} l’initialisation aux alternatives, sauf si vous avez une bonne raison de ne pas le faire.
Il existe de nombreuses raisons d'utiliser l'initialisation d'accolade, mais vous devez savoir que le constructeur initializer_list<>
est préféré aux autres constructeurs, l'exception étant le constructeur par défaut. Cela pose des problèmes avec les constructeurs et les modèles où le constructeur de type T
peut être une liste d'initialiseurs ou un ancien ctor.
struct Foo {
Foo() {}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer list" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
};
int main() {
Foo a;
Foo b(a); // copy ctor
Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
En supposant que vous ne rencontriez pas de telles classes, il y a peu de raisons de ne pas utiliser la liste d'intializer.
Il existe déjà d'excellentes réponses sur les avantages de l'initialisation de liste. Toutefois, ma règle personnelle est de NE PAS utiliser d'accolades autant que possible, mais plutôt de le rendre dépendant du sens conceptuel:
D'après mon expérience, ce jeu de règles peut être appliqué de manière beaucoup plus cohérente que l'utilisation d'accolades par défaut, mais vous devez vous rappeler explicitement de toutes les exceptions lorsqu'elles ne peuvent pas être utilisées ou ont un sens différent de celui de la syntaxe d'appel de fonction "normale" avec parenthèse. (appelle une surcharge différente).
Il par exemple s'intègre parfaitement avec les types de bibliothèques standard tels que std::vector
:
vector<int> a{10,20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10,20); //Parenthesis -> uses arguments to parametrize some functionality,
vector<int> c(it1,it2); //like filling the vector with 10 integers or copying a range.
vector<int> d{}; //empty braces -> default constructs vector, which is equivalent
//to a vector that is filled with zero elements