Já existem ótimas respostas sobre as vantagens de usar a inicialização de lista, no entanto, minha regra pessoal NÃO é usar chaves sempre que possível, mas torná-la dependente do significado conceitual:
- Se o objeto que estou criando conceitualmente mantém os valores que estou passando no construtor (por exemplo, contêineres, estruturas de POD, atômica, ponteiros inteligentes etc.), então estou usando os chavetas.
- Se o construtor se assemelhar a uma chamada de função normal (ele executa algumas operações mais ou menos complexas que são parametrizadas pelos argumentos), então estou usando a sintaxe da chamada de função normal.
- Para inicialização padrão, eu sempre uso chaves.
Por um lado, dessa forma, eu sempre tenho certeza de que o objeto é inicializado, independentemente de, por exemplo, ser uma classe "real" com um construtor padrão que seria chamado assim mesmo ou um tipo interno / POD. Segundo, é - na maioria dos casos - consistente com a primeira regra, pois um objeto inicializado padrão geralmente representa um objeto "vazio".
Na minha experiência, esse conjunto de regras pode ser aplicado de maneira muito mais consistente do que usar chaves, por padrão, mas ter que lembrar explicitamente todas as exceções quando elas não puderem ser usadas ou tiverem um significado diferente da sintaxe "normal" de chamada de função com parênteses (chama uma sobrecarga diferente).
Por exemplo, ele se encaixa muito bem com os tipos de biblioteca padrão, como std::vector
:
vector<int> a{10,20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10,20); //Parentheses -> 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
auto
?