with initialize argument c++ c++11 initialization

argument - c++ initialize class with parameters



¿Inicializando correctamente las variables en C++ moderno(C++ 11 y superior), usando() o{}? (7)

En primer lugar, parece que hay una confusión terminológica. Lo que tienes no es inicialización de valores. La inicialización del valor ocurre cuando no proporciona ningún argumento de inicialización explícito. int x; utiliza la inicialización por defecto, el valor de x no será especificado. int x{}; usa la inicialización del valor, x será 0 . int x(); declara una función, por eso se prefiere {} para la inicialización de valores.

El código que has mostrado no utiliza la inicialización de valores. Con auto , lo más seguro es utilizar la inicialización de copia:

auto q = p;

Las páginas de referencia de C ++ dicen que () es para la inicialización del valor, {} es para el valor y el agregado y la inicialización de la lista. Entonces, si solo quiero inicialización de valor, ¿cuál uso? () o {}? Lo pregunto porque en el libro "A Tour of C ++" del mismo Bjarne, parece preferir usar {}, incluso para la inicialización de valores (consulte, por ejemplo, las páginas 6 y 7), por lo que pensé que era una buena práctica siempre use {}, incluso para la inicialización del valor. Sin embargo , he estado muy mordido por el siguiente error recientemente. Considere el siguiente código.

auto p = std::make_shared<int>(3); auto q{ p }; auto r(p);

Ahora de acuerdo con el compilador (Visual Studio 2013), q tiene el tipo std::initializer_list<std::shared_ptr<int>> , que no es lo que pretendía. Lo que realmente pretendía para q es en realidad lo que r es, que es std::shared_ptr<int> . Entonces, en este caso, no debería usar {} para la inicialización del valor, sino usar (). Dado esto, ¿por qué Bjarne en su libro todavía parece preferir usar {} para la inicialización de valores? Por ejemplo, usa double d2{2.3} en la parte inferior de la página 6.

Para responder definitivamente a mis preguntas, ¿cuándo debo usar () y cuándo debo usar {}? ¿Y es una cuestión de corrección de sintaxis o una buena práctica de programación?

Oh y uh, claro inglés si es posible por favor.

EDITAR: Parece que he malinterpretado un poco la inicialización del valor (vea las respuestas a continuación). Sin embargo, las preguntas anteriores siguen en pie y en grande.


Esta es mi opinión.

Cuando se usa auto como especificador de tipo, es más limpio usar:

auto q = p; // Type of q is same as type of p auto r = {p}; // Type of r is std::initializer_list<...>

Cuando se usa un especificador de tipo explícito, es mejor usar {} lugar de () .

int a{}; // Value initialized to 0 int b(); // Declares a function (the most vexing parse)

Uno podría usar

int a = 0; // Value initialized to 0

Sin embargo, la forma

int a{};

también se puede utilizar para valorar inicializar objetos de tipos definidos por el usuario. P.ej

struct Foo { int a; double b; }; Foo f1 = 0; // Not allowed. Foo f1{}; // Zero initialized.


Hay otra diferencia importante: el inicializador de llaves requiere que el tipo dado realmente pueda mantener el valor dado. En otras palabras, prohíbe el estrechamiento del valor, como el redondeo o el truncamiento.

int a(2.3); // ok? a will hold the value 2, no error, maybe compiler warning uint8_t c(256); // ok? the compiler should warn about something fishy going on

En comparación con la inicialización de corsé

int A{2.3}; // compiler error, because int can NOT hold a floating point value double B{2.3}; // ok, double can hold this value uint8_t C{256}; // compiler error, because 8bit is not wide enough for this number

Especialmente en la programación genérica con plantillas, debe utilizar la inicialización de llaves para evitar sorpresas desagradables cuando el tipo subyacente hace algo inesperado en sus valores de entrada.


Herb Sutter parece estar haciendo una discusión en CppCon 2014 (39:25 en la charla) por el uso de inicializadores automáticos y de refuerzo, de esta manera:

auto x = MyType { initializers };

siempre que quiera forzar el tipo, para una consistencia de izquierda a derecha en las definiciones:

  • Tipo deducido: auto x = getSomething()
  • Tipo coaccionado: auto x = MyType { blah }
  • Literales definidos por el usuario auto x = "Hello, world."s
  • Declaración de función: auto f { some; commands; } -> MyType auto f { some; commands; } -> MyType
  • Llamado Lambda: using auto f = [=]( { some; commands; } -> MyType
  • C ++ 11-style using AnotherType = SomeTemplate<MyTemplateArg> : using AnotherType = SomeTemplate<MyTemplateArg>


Scott Meyers tiene bastante que decir acerca de la diferencia entre los dos métodos de inicialización en su libro Effective Modern C ++ .

Resume ambos enfoques como este:

La mayoría de los desarrolladores terminan eligiendo un tipo de delimitador por defecto, utilizando el otro solo cuando tienen que hacerlo. Las personas que no están a la par de la llave por defecto se sienten atraídas por su amplitud incomparable de aplicabilidad, su prohibición de reducir las conversiones y su inmunidad al análisis más desconcertante de C ++. Estas personas entienden que en algunos casos (por ejemplo, la creación de un std::vector con un tamaño y un valor de elemento inicial dados), se requieren paréntesis. Por otro lado, la multitud go-parentheses-go abarca paréntesis como su delimitador de argumentos predeterminado. Se sienten atraídos por su coherencia con la tradición sintáctica de C ++ 98, su evitación del problema auto-deduced-a-std :: initializer_list, y el conocimiento de que sus llamadas de creación de objetos no serán inadvertidamente ignoradas por std::initializer_list constructores std::initializer_list . Reconocen que, a veces, solo los frenos funcionan (por ejemplo, al crear un contenedor con valores particulares). No existe consenso en cuanto a que cualquiera de los dos enfoques es mejor que el otro, por lo que mi consejo es elegir uno y aplicarlo de manera coherente.


{} es la inicialización de valor si está vacía, si no es la inicialización de lista / agregación.

Del borrador, 7.1.6.4 auto especificador, 7 / ... Ejemplo ,

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

Las reglas son un poco complejas de explicar aquí (¡incluso difíciles de leer de la fuente!).