Namespaces
Variants

Initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Inicialización de una variable proporciona su valor inicial en el momento de la construcción.

El valor inicial puede proporcionarse en la sección de inicializador de un declarator o una new expression . También ocurre durante las llamadas a funciones: los parámetros de función y los valores de retorno de función también se inicializan.

Contenidos

Inicializadores

Para cada declarador, el initializer (si existe) puede ser uno de los siguientes:

= expresión (1)
= {}
= { lista-de-inicializadores }
= { lista-de-inicializadores-designados }
(2)

(desde C++20)
( lista-de-expresiones )
( lista-de-inicializadores )
(3) (hasta C++11)
(desde C++11)
{}
{ lista-de-inicializadores }
{ lista-de-inicializadores-designados }
(4) (desde C++11)
(desde C++11)
(desde C++20)
1) Sintaxis de inicialización por copia.
2) Sintaxis de inicialización de agregados. (hasta C++11) Sintaxis de inicialización de lista. (desde C++11)
3) Sintaxis de inicialización directa.
4) Sintaxis de inicialización de lista.
expression - cualquier expresión (excepto expresiones de coma sin paréntesis comma expressions )
expression-list - una lista separada por comas de expresiones (excepto expresiones de coma sin paréntesis)
initializer-list - una lista separada por comas de cláusulas de inicialización (ver abajo)
designated-initializer-list - una lista separada por comas de designated initializer clauses


Una cláusula de inicialización puede ser una de las siguientes:

expresión (1)
{} (2)
{ lista-de-inicializadores } (3)
{ lista-de-inicializadores-designados } (4) (desde C++20)

Sintaxis (2-4) se denominan colectivamente lista de inicializadores entre llaves .

Semántica del inicializador

Si no se especifica un inicializador para un objeto, el objeto es default-initialized . Si no se especifica un inicializador para una reference , el programa está mal formado.

Si el inicializador especificado para un objeto es ( ) (no puede aparecer en declaradores debido a la restricción sintáctica), el objeto es value-initialized . Si el inicializador especificado para una referencia es ( ) , el programa está mal formado.

La semántica de los inicializadores es la siguiente:

  • Si la entidad que se inicializa es una referencia, consulte reference initialization .
  • De lo contrario, la entidad que se inicializa es un objeto. Dado el tipo del objeto como T :
  • Si el inicializador es de sintaxis (2) :
(hasta C++11)
(desde C++11)
#include <string>
std::string s1;           // inicialización por defecto
std::string s2();         // NO es una inicialización!
                          // en realidad declara una función "s2"
                          // sin parámetros que retorna std::string
std::string s3 = "hello"; // inicialización por copia
std::string s4("hello");  // inicialización directa
std::string s5{'a'};      // inicialización por lista (desde C++11)
char a[3] = {'a', 'b'}; // inicialización de agregado
                        // (parte de la inicialización por lista desde C++11)
char& c = a[0];         // inicialización de referencia

Variables no locales

Todas las variables no locales con duración de almacenamiento estática se inicializan como parte del inicio del programa, antes de que comience la ejecución de la función main (a menos que se difiera, véase más abajo). Todas las variables no locales con duración de almacenamiento thread-local se inicializan como parte del lanzamiento del hilo, secuenciadas antes de que comience la ejecución de la función del hilo. Para ambas clases de variables, la inicialización ocurre en dos etapas distintas:

Inicialización estática

Existen dos formas de inicialización estática:

1) Si es posible, constant initialization es aplicada.
2) De lo contrario, las variables estáticas no locales y las variables locales de hilo son zero-initialized .

En la práctica:

  • La inicialización constante generalmente se aplica en tiempo de compilación. Las representaciones de objetos precalculadas se almacenan como parte de la imagen del programa. Si el compilador no hace esto, aún debe garantizar que la inicialización ocurra antes de cualquier inicialización dinámica.
  • Las variables que deben ser inicializadas a cero se colocan en el segmento .bss de la imagen del programa, que no ocupa espacio en disco y es puesto a cero por el SO al cargar el programa.

Inicialización dinámica

Después de que se completa toda la inicialización estática, la inicialización dinámica de variables no locales ocurre en las siguientes situaciones:

1) Inicialización dinámica no ordenada , que aplica únicamente a los miembros de datos estáticos de plantillas de clase (static/thread-local) y plantillas de variable (desde C++14) que no están explícitamente especializados . La inicialización de tales variables estáticas es secuenciada de manera indeterminada con respecto a toda otra inicialización dinámica excepto si el programa inicia un thread antes de que una variable sea inicializada, en cuyo caso su inicialización no está secuenciada (desde C++17) . La inicialización de tales variables thread-local no está secuenciada con respecto a toda otra inicialización dinámica.
2) Inicialización dinámica parcialmente ordenada , que se aplica a todas las variables inline que no son una especialización implícita o explícitamente instanciada. Si una V parcialmente ordenada se define antes que una W ordenada o parcialmente ordenada en cada unidad de traducción, la inicialización de V se secuencia antes de la inicialización de W (o sucede-antes, si el programa inicia un hilo).
(desde C++17)
3) Inicialización dinámica ordenada , que se aplica a todas las demás variables no locales: dentro de una única unidad de traducción, la inicialización de estas variables siempre está secuenciada en el orden exacto en que sus definiciones aparecen en el código fuente. La inicialización de variables estáticas en diferentes unidades de traducción está indeterminadamente secuenciada. La inicialización de variables locales a hilo en diferentes unidades de traducción no está secuenciada.

Si la inicialización de una variable no local con duración de almacenamiento estática o de hilo termina mediante una excepción, std::terminate es llamado.

Inicialización dinámica temprana

Los compiladores pueden inicializar variables de inicialización dinámica como parte de la inicialización estática (esencialmente, en tiempo de compilación), si se cumplen las siguientes dos condiciones:

1) la versión dinámica de la inicialización no cambia el valor de ningún otro objeto de ámbito de namespace antes de su inicialización
2) la versión estática de la inicialización produce el mismo valor en la variable inicializada que el que produciría la inicialización dinámica si todas las variables no requeridas para ser inicializadas estáticamente fueran inicializadas dinámicamente.

Debido a la regla anterior, si la inicialización de algún objeto o1 hace referencia a un objeto de ámbito de espacio de nombres o2 , que potencialmente requiere inicialización dinámica, pero está definido más adelante en la misma unidad de traducción, no está especificado si el valor de o2 utilizado será el valor del o2 completamente inicializado (porque el compilador promovió la inicialización de o2 a tiempo de compilación) o será el valor de o2 simplemente inicializado a cero.

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;   // no especificado:
                  // inicializado dinámicamente a 0.0 si d1 se inicializa dinámicamente, o
                  // inicializado dinámicamente a 1.0 si d1 se inicializa estáticamente, o
                  // inicializado estáticamente a 0.0 (porque ese sería su valor
                  // si ambas variables se inicializaran dinámicamente)
double d1 = fd(); // puede inicializarse estática o dinámicamente a 1.0

Inicialización dinámica diferida

Es definido por la implementación si la inicialización dinámica ocurre-antes de la primera sentencia de la función main (para estáticos) o la función inicial del hilo (para thread-locals), o se difiere para ocurrir después.

Si la inicialización de una variable no inline (since C++17) se difiere para ocurrir después de la primera sentencia de la función main/hilo, ocurre antes del primer ODR-use de cualquier variable con duración de almacenamiento static/thread definida en la misma unidad de traducción que la variable a inicializar. Si ninguna variable o función es ODR-used desde una unidad de traducción dada, las variables no locales definidas en esa unidad de traducción podrían nunca inicializarse (esto modela el comportamiento de una biblioteca dinámica bajo demanda). Sin embargo, siempre que cualquier elemento de una unidad de traducción sea ODR-used, todas las variables no locales cuya inicialización o destrucción tenga efectos secundarios se inicializarán incluso si no se usan en el programa.

Si la inicialización de una variable inline se difiere, ocurre antes del primer ODR-use de esa variable específica.

(since C++17)
// ============
// == Archivo 1 ==
#include "a.h"
#include "b.h"
B b;
A::A() { b.Use(); }
// ============
// == Archivo 2 ==
#include "a.h"
A a;
// ============
// == Archivo 3 ==
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main()
{
    a.Use();
    b.Use();
}
// Si a se inicializa antes de que se entre en main, b podría seguir sin inicializarse
// en el punto donde A::A() lo utiliza (porque la inicialización dinámica está
// indeterminadamente secuenciada entre unidades de traducción)
// Si a se inicializa en algún punto después de la primera sentencia de main (que odr-utiliza
// una función definida en el Archivo 1, forzando a que su inicialización dinámica se ejecute),
// entonces b se inicializará antes de su uso en A::A

Variables locales estáticas

Para la inicialización de variables estáticas locales (es decir, de ámbito de bloque) y variables locales de hilo, consulte static block variables .

No se permite un inicializador en una declaración de variable con ámbito de bloque con vinculación externa o interna . Dicha declaración debe aparecer con extern y no puede ser una definición.

Miembros de clase

Los miembros de datos no estáticos pueden inicializarse con lista de inicialización de miembros o con un inicializador de miembro predeterminado .

Notas

El orden de destrucción de las variables no locales se describe en std::exit .

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Se aplica a Comportamiento publicado Comportamiento correcto
CWG 270 C++98 el orden de inicialización de miembros de datos estáticos
de plantillas de clase no estaba especificado
especificado como no ordenado excepto para
especializaciones y definiciones explícitas
CWG 441 C++98 las referencias no locales con duración de almacenamiento estático
no siempre se inicializaban antes de las inicializaciones dinámicas
consideradas como inicialización estática, siempre
inicializadas antes de las inicializaciones dinámicas
CWG 1415 C++98 una declaración de variable extern de ámbito de bloque
podría ser una definición
prohibido (no se permite inicializador
en dichas declaraciones)
CWG 2599 C++98 no estaba claro si evaluar argumentos de función
en el inicializador es parte de la inicialización
es parte de la inicialización

Véase también

Documentación de C para Inicialización