Initialization
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) |
|||||||
| 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 (1) , el objeto es copy-initialized .
|
(hasta C++11) |
|
(desde C++11) |
-
- Si el inicializador es de sintaxis (3) , el objeto es direct-initialized .
#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:
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
.bssde 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:
|
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) |
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:
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
- copy elision
- converting constructor
- copy constructor
- default constructor
-
explicit - move constructor
-
new
|
Documentación de C
para
Inicialización
|