Value-initialization
Esta es la inicialización realizada cuando un objeto se construye con un inicializador vacío.
Contenidos |
Sintaxis
T
()
|
(1) | ||||||||
new
T
()
|
(2) | ||||||||
Class
::
Class
(
...
)
:
member
()
{
...
}
|
(3) | ||||||||
T
object
{};
|
(4) | (desde C++11) | |||||||
T
{}
|
(5) | (desde C++11) | |||||||
new
T
{}
|
(6) | (desde C++11) | |||||||
Class
::
Class
(
...
)
:
member
{}
{
...
}
|
(7) | (desde C++11) | |||||||
Explicación
La inicialización por valor se realiza en estas situaciones:
En todos los casos, si se utiliza el par de llaves vacío
{}
y
T
es un tipo agregado,
aggregate initialization
se realiza en lugar de value-initialization.
|
Si
|
(since C++11) |
Los efectos de la inicialización por valor son:
-
Si
Tes un tipo clase (posiblemente calificado con cv):
-
-
Si la inicialización por defecto para
Tselecciona un constructor , y el constructor no es declarado por el usuario (hasta C++11) proporcionado por el usuario (desde C++11) , el objeto es primero zero-initialized . - En cualquier caso, el objeto es default-initialized .
-
Si la inicialización por defecto para
-
De lo contrario, si
Tes un tipo de arreglo, cada elemento del arreglo es inicializado por valor. - De lo contrario, el objeto es inicializado a cero.
Notas
La sintaxis
T object
(
)
;
no inicializa un objeto; declara una función que no toma argumentos y retorna
T
. La forma de inicializar por valor una variable nombrada antes de C++11 era
T object
=
T
(
)
;
, que inicializa por valor un temporal y luego inicializa por copia el objeto: la mayoría de compiladores
optimizan la copia
en este caso.
Las referencias no pueden ser inicializadas por valor.
Como se describe en
function-style cast
, la sintaxis
T
(
)
(1)
está prohibida si
T
nombra un array type, mientras que
T
{
}
(5)
está permitida.
Todos los contenedores estándar (
std::vector
,
std::list
, etc.) inicializan por valor sus elementos cuando se construyen con un único
argumento
size_type
o cuando se expanden mediante una llamada a
resize
(
)
, a menos que su asignador personalice el comportamiento de
construct
.
Ejemplo
#include <cassert> #include <iostream> #include <string> #include <vector> struct T1 { int mem1; std::string mem2; virtual void foo() {} // asegura que T1 no sea un agregado }; // constructor por defecto implícito struct T2 { int mem1; std::string mem2; T2(const T2&) {} // constructor de copia proporcionado por el usuario }; // sin constructor por defecto struct T3 { int mem1; std::string mem2; T3() {} // constructor por defecto proporcionado por el usuario }; std::string s{}; // clase => inicialización por defecto, el valor es "" int main() { int n{}; // escalar => inicialización a cero, el valor es 0 assert(n == 0); double f = double(); // escalar => inicialización a cero, el valor es 0.0 assert(f == 0.0); int* a = new int[10](); // array => inicialización por valor de cada elemento assert(a[9] == 0); // el valor de cada elemento es 0 T1 t1{}; // clase con constructor por defecto implícito => assert(t1.mem1 == 0); // t1.mem1 es inicializado a cero, el valor es 0 assert(t1.mem2 == ""); // t1.mem2 es inicializado por defecto, el valor es "" // T2 t2{}; // error: clase sin constructor por defecto T3 t3{}; // clase con constructor por defecto proporcionado por el usuario => std::cout << t3.mem1; // t3.mem1 es inicializado por defecto a valor indeterminado assert(t3.mem2 == ""); // t3.mem2 es inicializado por defecto, el valor es "" std::vector<int> v(3); // inicialización por valor de cada elemento assert(v[2] == 0); // el valor de cada elemento es 0 std::cout << '\n'; delete[] a; }
Salida posible:
42
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 178 | C++98 |
no existía la inicialización por valor; el inicializador vacío invocaba
inicialización por defecto (aunque new T ( ) también realizaba inicialización a cero) |
el inicializador vacío invoca
inicialización por valor |
| CWG 543 | C++98 |
la inicialización por valor para un objeto de clase sin constructores
proporcionados por el usuario equivalía a inicializar por valor cada subobjeto (lo que no necesitaba inicializar a cero un miembro con constructor por defecto proporcionado por el usuario) |
inicializa a cero
todo el objeto, luego llama al constructor por defecto |
| CWG 1301 | C++11 |
la inicialización por valor de uniones con constructores por defecto
eliminados resultaba en inicialización a cero |
se realiza
inicialización por defecto |
| CWG 1368 | C++98 |
cualquier constructor proporcionado por el usuario causaba
que se omitiera la inicialización a cero |
solo un constructor por defecto
proporcionado por el usuario omite la inicialización a cero |
| CWG 1502 | C++11 |
inicializar por valor una unión sin constructor por defecto
proporcionado por el usuario solo inicializaba a cero el objeto, a pesar de los inicializadores de miembro por defecto |
realiza inicialización
por defecto después de la inicialización a cero |
| CWG 1507 | C++98 |
la inicialización por valor para un objeto de clase sin ningún
constructor proporcionado por el usuario no verificaba la validez del constructor por defecto cuando este es trivial |
se verifica la validez del
constructor por defecto trivial |
| CWG 2820 | C++98 |
la inicialización por defecto que seguía a la inicialización
a cero requería un constructor no trivial |
no requerido |
| CWG 2859 | C++98 |
la inicialización por valor para un objeto de clase podría involucrar
inicialización a cero incluso si la inicialización por defecto no selecciona realmente un constructor proporcionado por el usuario |
no hay
inicialización a cero en este caso |