MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
¿Por qué?
No pude encontrar una respuesta en SO, así que déjame responder mi propia pregunta.
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
¿Por qué?
No pude encontrar una respuesta en SO, así que déjame responder mi propia pregunta.
auto
?std::map<std::string, std::vector<std::string>>::const_iterator
gustaría hablar contigo.using MyContainer = std::map<std::string, std::vector<std::string>>;
es aún mejor (¡especialmente porque puedesRespuestas:
Básicamente copiando y pegando de "The C ++ Programming Language 4th Edition" de Bjarne Stroustrup :
La inicialización de la lista no permite el estrechamiento (§iso.8.5.4). Es decir:
Ejemplo:
La única situación en la que se prefiere = sobre {} es cuando se usa la
auto
palabra clave para obtener el tipo determinado por el inicializador.Ejemplo:
Conclusión
Prefiere la inicialización {} sobre las alternativas a menos que tengas una buena razón para no hacerlo.
fuente
()
se puede analizar como una declaración de función. Es confuso e inconsistente lo que puedes decirT t(x,y,z);
pero noT t()
. Y a veces, estás segurox
, ni siquiera puedes decirloT t(x);
.std::initializer_list
. RedXIII menciona este problema (y simplemente lo ignora), mientras que lo ignora por completo.A(5,4)
yA{5,4}
puede llamar a funciones completamente diferentes, y esto es algo importante para saber. Incluso puede dar lugar a llamadas que parecen poco intuitivas. Decir que deberías preferir{}
por defecto hará que la gente no entienda lo que está sucediendo. Sin embargo, esto no es tu culpa. Personalmente, creo que es una característica extremadamente mal pensada.auto var{ 5 }
y se deducirá comoint
no másstd::initializer_list<int>
.Ya hay excelentes respuestas sobre las ventajas de usar la inicialización de la lista, sin embargo, mi regla general personal es NO usar llaves siempre que sea posible, sino que dependerá del significado conceptual:
Por un lado, de esa manera siempre estoy seguro de que el objeto se inicializa independientemente de si es, por ejemplo, una clase "real" con un constructor predeterminado que se llamaría de todos modos o un tipo incorporado / POD. En segundo lugar, es, en la mayoría de los casos, coherente con la primera regla, ya que un objeto inicializado predeterminado a menudo representa un objeto "vacío".
En mi experiencia, este conjunto de reglas se puede aplicar de manera mucho más consistente que el uso de llaves por defecto, pero tener que recordar explícitamente todas las excepciones cuando no se pueden usar o tienen un significado diferente que la sintaxis de llamada de función "normal" con paréntesis (Llama a una sobrecarga diferente).
Por ejemplo, encaja perfectamente con tipos de biblioteca estándar como
std::vector
:fuente
const int &b{}
<- no intenta crear una referencia no inicializada, sino que la vincula a un objeto entero temporal. Segundo ejemplo:struct A { const int &b; A():b{} {} };
<- no intenta crear una referencia no inicializada (como()
lo haría), sino que la vincula a un objeto entero temporal y luego lo deja colgando. GCC incluso con-Wall
no advierte para el segundo ejemplo.Hay MUCHAS razones para usar la inicialización de llaves, pero debe tener en cuenta que el
initializer_list<>
constructor es preferido a los otros constructores , la excepción es el constructor predeterminado. Esto conduce a problemas con los constructores y las plantillas, donde elT
constructor de tipos puede ser una lista de inicializadores o un viejo ctor simple.Suponiendo que no encuentre tales clases, hay pocas razones para no usar la lista de inicializadores.
fuente
{ ... }
) a menos que desee lainitializer_list
semántica (bueno, y tal vez para la construcción predeterminada de un objeto).std::initializer_list
existe la regla, solo agrega confusión y desorden al lenguaje. ¿Qué tiene de malo hacerFoo{{a}}
si quieres elstd::initializer_list
constructor? Parece mucho más fácil de entender que tenerstd::initializer_list
prioridad sobre todas las demás sobrecargas.Foo{{a}}
sigue algo de lógica para mí mucho más de loFoo{a}
que se convierte en la prioridad de la lista inicializadora (ups podría el usuario pensar hm ...)std::initializer_list<Foo>
constructor, pero se va a agregar alFoo
clase en algún momento para extender su interfaz? Entonces los usuarios de laFoo
clase están jodidos.initializer_list<>
), que realmente no califica quién dice que es preferida, y luego procede a mencionar un buen caso donde NO es preferida. ¿Qué me estoy perdiendo que ~ otras 30 personas (a partir del 21/04/2016) encontraron útil?Solo es más seguro siempre que no construyas con -Ninguna reducción como lo hace Google en Chromium. Si lo hace, entonces es MENOS seguro. Sin esa bandera, los únicos casos inseguros serán corregidos por C ++ 20.
Nota: A) Las llaves son más seguras porque no permiten el estrechamiento. B) Los brackers rizados son menos seguros porque pueden omitir constructores privados o eliminados, y llamar implícitamente a constructores marcados explícitamente.
Esos dos combinados significan que son más seguros si lo que hay dentro son constantes primitivas, pero menos seguros si son objetos (aunque se arreglan en C ++ 20)
fuente