MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Por quê?
Não consegui encontrar uma resposta no SO, então deixe-me responder minha própria pergunta.
c++
c++11
syntax
initialization
list-initialization
Oleksiy
fonte
fonte
auto
?std::map<std::string, std::vector<std::string>>::const_iterator
gostaria de uma palavra com você.using MyContainer = std::map<std::string, std::vector<std::string>>;
é ainda melhor (especialmente como você pode molde ele!)Respostas:
Basicamente, copia e cola do "The C ++ Programming Language 4th Edition" de Bjarne Stroustrup :
A inicialização da lista não permite restringir (§iso.8.5.4). Isso é:
Exemplo:
A única situação em que = é preferível a {} é ao usar a
auto
palavra-chave para obter o tipo determinado pelo inicializador.Exemplo:
Conclusão
Prefira a inicialização {} sobre as alternativas, a menos que você tenha um forte motivo para não fazê-lo.
fonte
()
pode ser analisado como uma declaração de função. É confuso e inconsistente que você pode dizer,T t(x,y,z);
mas não éT t()
. E, às vezes, com certezax
, você nem pode dizerT t(x);
.std::initializer_list
. O RedXIII menciona esse problema (e apenas o ignora), enquanto você o ignora completamente.A(5,4)
eA{5,4}
pode chamar funções completamente diferentes, e isso é uma coisa importante a saber. Pode até resultar em chamadas que parecem não intuitivas. Dizer que você deve preferir{}
por padrão fará com que as pessoas não entendam o que está acontecendo. Isso não é sua culpa, no entanto. Pessoalmente, acho que é um recurso extremamente mal pensado.auto var{ 5 }
e será deduzido comoint
nãostd::initializer_list<int>
.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:
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
:fonte
const int &b{}
<- não tenta criar uma referência não inicializada, mas a vincula a um objeto inteiro temporário. Segundo exemplo:struct A { const int &b; A():b{} {} };
<- não tenta criar uma referência não inicializada (como()
faria), mas vincula-a a um objeto inteiro temporário e, em seguida, deixa-a pendente. O GCC, mesmo com-Wall
, não adverte para o segundo exemplo.Existem MUITAS razões para usar a inicialização entre parênteses, mas você deve estar ciente de que o
initializer_list<>
construtor é preferido aos outros construtores , a exceção sendo o construtor padrão. Isso leva a problemas com construtores e modelos nos quais oT
construtor de tipos pode ser uma lista de inicializadores ou um ctor antigo simples.Supondo que você não encontre essas classes, há poucas razões para não usar a lista do inicializador.
fonte
{ ... }
), a menos que você queira ainitializer_list
semântica (bem, e talvez para a construção padrão de um objeto).std::initializer_list
regra existe - apenas acrescenta confusão e confusão ao idioma. O que há de errado em fazerFoo{{a}}
se você deseja ostd::initializer_list
construtor? Isso parece muito mais fácil de entender do que terstd::initializer_list
precedência sobre todas as outras sobrecargas.Foo{{a}}
segue alguma lógica para mim muito mais doFoo{a}
que se transforma em intializer lista de precedência (ups pode o usuário acha hm ...)std::initializer_list<Foo>
construtor, mas ele for adicionado àFoo
classe em algum momento para estender sua interface? Então os usuários daFoo
classe estão ferrados.initializer_list<>
), que não qualifica quem diz que é o preferido, e depois menciona um bom caso em que NÃO é o preferido. O que estou sentindo falta de que ~ 30 outras pessoas (em 21/04/2016) foram úteis?É mais seguro, desde que você não construa com o -Wno-estreitando, como o Google faz no Chromium. Se o fizer, é MENOS seguro. Sem esse sinalizador, os únicos casos inseguros serão corrigidos pelo C ++ 20.
Nota: A) Os colchetes são mais seguros porque não permitem o estreitamento. B) Os brackers encaracolados são menos seguros porque podem ignorar construtores particulares ou excluídos e chamar implicitamente marcadores explícitos.
Esses dois combinados significam que eles são mais seguros se o que está dentro são constantes primitivas, mas menos seguros se forem objetos (embora fixados no C ++ 20)
fonte