Inicialización de un valor(desde C++03)
Esta es la inicialización que se realiza cuando se construye una variable con un inicializador vacío.
Contenido |
[editar] Sintaxis
T()
|
(1) | ||||||||
new T ()
|
(2) | ||||||||
Clase:: Clase( ...) : miembro() { ... }
|
(3) | ||||||||
T object {};
|
(4) | (desde C++11) | |||||||
T{}
|
(5) | (desde C++11) | |||||||
new T {}
|
(6) | (desde C++11) | |||||||
Clase:: Clase( ...) : miembro{} { ... }
|
(7) | (desde C++11) | |||||||
[editar] Explicación
La inicialización de un valor se realiza en estas situaciones:
new
con un inicializador que consiste en un par de paréntesis vacío o un par de llaves vacío (desde C++11);
4) Cuando una variable nombrada (automática, estática o local al hilo) se declara con un inicializador que consiste en un par de llaves.
|
(desde C++11) |
En todos los casos, si el par de llaves vacío {}
se usa y T
es un tipo de agregado, se realiza la inicialización de agregado en lugar de la inicialización de un valor.
Si T
es un tipo de clase que no tiene un constructor por defecto pero tiene un constructor que toma una lista de inicializadores (std::initializer_list), se realiza la inicialización de lista.
Los efectos de la inicialización de un valor son:
1) si
T es un tipo de clase con al menos un constructor de cualquier tipo proporcionado por el usuario, se llama al constructor por defecto;2) si T es un tipo de clase no unión sin ningún constructor proporcionado por el usuario, cada dato miembro no estático y componente de clase base de T se inicializa mediante la inicialización de un valor;
|
(hasta C++11) |
1) si
T es un tipo de clase sin un constructor por defecto o con un constructor por defecto proporcionado por el usuario o eliminado (= delete), el objeto se inicializa mediante la inicialización por defecto;2) si T es un tipo de clase con un constructor por defecto que ni es proporcionado por el usuario ni eliminado (es decir, puede ser una clase con un constructor por defecto definido implícitamente o marcado con = default, el objeto se inicializa mediante la inicialización a cero y luego se inicializa mediante la inicialización por defecto si tiene un constructor por defecto no trivial;
|
(desde C++11) |
T
es un tipo de array, cada elemento del array se inicializa mediante la inicialización de un valor;[editar] Notes
Un constructor es proporcionado por el usuario si está declarado por el usuario y no está explícitamente marcado con = default en su primera declaración.
La sintaxis T object(); no inicializa un objeto; declara una función que no toma argumentos y devuelve T
. La forma de inicializar el valor de una variable con nombre antes de C++11 era T object = T();, que inicializa el valor un temporal y luego inicializa mediante la inicialización de copia el objeto: la mayoría de los compiladores optimizan eliminando la copia en este caso.
En C++98 anterior a C++03 (que introdujo la inicialización de un valor), la expresión new T() se clasificó como inicialización por defecto y especificó la inicialización cero.
Las referencias no se pueden inicializarse mediante la inicialización de un valor.
Como se describe en conversión funcional, la sintaxis T() (1) está prohibida para arrays, mientras que T{} (5) está permitida.
Todos los contenedores estándar (std::vector, std::list, etc.) inicializan sus elementos mediante la inicialización de un valor cuando se construyen con un solo argumento size_type
o cuando crecen mediante una llamada a resize().
Desde C++11, la inicialización de una clase sin un constructor proporcionado por el usuario mediante la inicialización de un valor, la cual tiene un miembro de un tipo de clase con un constructor proporcionado por el usuario, pone a cero al miembro antes de llamar a su constructor:
struct A { int i; A() { } // ctor por defecto prop. por el usuario, no inicializa a i }; struct B { A a; }; // ctor por defecto implícitamente definido std::cout << B().a.i << '\n'; // inicialización de un valor de B a un temporal // deja b.a.i sin inicializar en C++03 // establece b.a.i a cero en C++11 // (observa que B{}.a.i deja a b.a.i sin inicializar en C++11, pero por // una razón diferente: en pos-DR1301 C++11, B{} es inicialización de agregado, // que entonces inicializa a A mediante inicialización de un valor, // que tiene un ctor proporcionado por el usuario)
[editar] Ejemplo
#include <string> #include <vector> #include <iostream> struct T1 { int mem1; std::string mem2; }; // ctor por defecto implícito struct T2 { int mem1; std::string mem2; T2(const T2&) { } // ctor de copia prop. por el usuario }; // no existe ctor por defecto struct T3 { int mem1; std::string mem2; T3() { } // ctor por defecto prop. por el usuario }; std::string s{}; // class => inicialización por defecto, el valor es "" int main() { int n{}; // escalar => inicialización cero, el valor es 0 double f = double(); // escalar => inicialización cero, el valor es 0.0 int* a = new int[10](); // array => inic. de un valor de cada elemento // el valor de cada elemento es 0 T1 t1{}; // clase con ctor por defecto implícito => // t1.mem1 es inicializada a cero, el valor es 0 // t1.mem2 es inicializada por defecto, el valor es "" // T2 t2{}; // ERROR: clase sin ctor por defecto T3 t3{}; // clase con ctor por defecto prop por el usuario => // t3.mem1 es inicializada por defecto a un valor inderterminado // t3.mem2 es inicializada por defecto, el valor es "" std::vector<int> v(3); // inic. de un valor de cada elemento // el valor de cada elemento es 0 std::cout << s.size() << ' ' << n << ' ' << f << ' ' << a[9] << ' ' << v[2] << '\n'; std::cout << t1.mem1 << ' ' << t3.mem1 << '\n'; delete[] a; }
Posible salida:
0 0 0 0 0 0 4199376
[editar] Infomes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 1301 | C++11 | Un constructor por defecto marcado con = default se saltaba la inicialización cero antes de la construcción. |
Se realiza la inicialización cero. |