Diferencia de inicialización con o sin llaves en C++

5 minutos de lectura

avatar de usuario
diversión tecnológica

Podemos inicializar la variable de dos formas en C++

Una:

int abc = 7;

Dos:

int abc {7};

¿Cuál es la diferencia entre estos dos métodos? ¿El compilador los trata de manera diferente o hay una diferencia en la forma en que se ejecuta el código?

  • es.cppreference.com/w/cpp/language/initialization

    – chris

    15 de enero de 2014 a las 23:08


  • Para int específicamente, la única diferencia es que {} prohíbe la conversión restringida, por ejemplo, de un literal que es demasiado grande para caber en un int. Para los tipos de clase, puede complicarse dependiendo de qué tan detallado desee conocer las diferencias.

    – mojar

    15 de enero de 2014 a las 23:09

Version corta

Inicialización vía {..} es la inicialización de lista, que prohíbe la reducción de conversiones. Por ejemplo, si LLONG_MAX es el valor máximo de un long long inty tu int no puede representar que:

int x = LLONG_MAX;  // probably accepted with a warning
int x {LLONG_MAX};  // error

Similarmente:

long long y = /*something*/;

int x = y;  // accepted, maybe with a warning
int x {y};  // error

Versión larga

Una inicialización del formulario.

T x = a;

es copia-inicialización; una inicialización de cualquier forma

T x(a);
T x{a};

es inicialización directa, [dcl.init]/15-16.

[dcl.init]/14 luego dice:

La forma de inicialización (usando paréntesis o =) es generalmente insignificante, pero importa cuando el inicializador o la entidad que se inicializa tiene un tipo de clase; vea abajo.

Entonces, para los tipos que no son de clase, el forma de la inicialización no importa. Sin embargo, hay una diferencia entre estas dos inicializaciones directas:

T x(a);  // 1
T x{a};  // 2

y de manera similar, entre estas dos inicializaciones de copia:

T x = a;    // 1
T x = {a};  // 2

Es decir, los que tienen {..} usar inicialización de lista. los {..} se llama un braced-init-list.

Entonces, cuando comparas T x = a; a T x {a};existen dos diferencias: copia-vs. inicialización directa, y “no-lista-” vs. inicialización de lista. Como ya mencionaron otros y en la cita anterior, para tipos que no son de clase T, no hay diferencia entre copy- y direct-init. Sin embargo, hay una diferencia entre list-init y no list-init. Es decir, también podríamos comparar

int x (a);
int x {a};

La inicialización de lista en este caso prohíbe la reducción de conversiones. Las conversiones restrictivas se definen en [dcl.init.list]/7 como:

Una conversión de estrechamiento es una conversión implícita

  • de un tipo de coma flotante a un tipo entero, o

  • de long double a double o floato de double a floatexcepto cuando la fuente sea una expresión constante y el valor real después de la conversión esté dentro del rango de valores que se pueden representar (incluso si no se puede representar exactamente), o

  • de un tipo entero o un tipo de enumeración sin ámbito a un tipo de punto flotante, excepto cuando el origen sea una expresión constante y el valor real después de la conversión se ajuste al tipo de destino y produzca el valor original cuando se vuelva a convertir al tipo original, o

  • desde un tipo entero o un tipo de enumeración sin ámbito hasta un tipo entero que no puede representar todos los valores del tipo original, excepto cuando el origen es una expresión constante cuyo valor después de las promociones integrales encajará en el tipo de destino.

  • ¿Qué pasa con este tipo de inicialización usando paréntesis y llaves? std::random_device{}() ?

    – mooooooooooooooooooooooo

    24 de enero de 2017 a las 9:16

  • @moooeeeep Este no es un tipo separado de inicialización. Construye un temporal de tipo std::random_device usando la expresión std::random_device{}y luego llama a ese objeto sobrecargado operator()al igual que std::random_device rd; rd() haría. los random_device tiene un operator() que invoca el RNG y devuelve un número (pseudo)aleatorio, consulte en.cppreference.com/w/cpp/numeric/random/random_device/…

    – mojar

    25 de enero de 2017 a las 8:33

  • ¡Genial gracias! Ahora que lo explicaste, parece obvio.

    – mooooooooooooooooooooooo

    25 de enero de 2017 a las 8:36

  • Traté de inicializar con int b1{2147483648}; . Pero no recibo el error, en su lugar solo recibo la advertencia “advertencia: reducción de la conversión de ‘2147483648ll’ de ‘long long int’ a ‘int’ dentro de { } [-Wnarrowing]|. ¿Por qué es así?

    – Rajesh

    9 oct 2017 a las 18:38

  • @Rajesh ¿Qué compilador y versión? Aparentemente, esto fue una advertencia solo hasta gcc 5. Ver también: gcc.gnu.org/bugzilla/show_bug.cgi?id=55783

    – mojar

    10 de octubre de 2017 a las 6:41


Mientras que para int las respuestas existentes están completas, yo penosamente descubrió que, en algunos casos, existen otras diferencias entre los () y {} inicializaciones.

La palabra clave es que {} es una lista de inicializadores.

Uno de esos casos es, el std::string inicialización con count copias de un char:

std::string stars(5, '*')

se inicializará stars como *****pero

std::string stars{5, '*'}

se leerá como std::string stars(char(5), '*') e inicializar estrella como * (precedido por un carácter oculto).

La primera es la inicialización de la copia, mientras que la segunda es la inicialización de la lista.

Pero, por lo general, la inicialización de copias se usa menos. Porque, si lo hace pasando objetos de tipos definidos por el usuario, solo causa una copia de bits y, por lo tanto, es posible que no produzca los resultados previstos si la clase definida por el usuario usa punteros.

  • No si tienen constructores de copias, ¿no? Estoy mucho más que confundido ahora.

    – RichieHH

    14/09/2021 a las 21:31

  • @RichieHH Si el tipo definido por el usuario tiene punteros, entonces uno debería preferir escribir el constructor de copia junto con el constructor y el destructor (Regla de 3). Pero, si no hay un constructor de copia, causará una ‘copia superficial’ y puede causar punteros colgantes.

    – yuvi

    15 de septiembre de 2021 a las 10:09

  • Exactamente. Los tipos definidos por el usuario que usan punteros deben tener constructores de copia e inicialización. Tal vez edite su respuesta. Gracias por volver.

    – RichieHH

    16 de septiembre de 2021 a las 5:06

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad