¿Inicialización predeterminada de std :: array?

103

Con C ++ 11 std::array, ¿tengo la garantía de que la sintaxis std::array<T, N> x;inicializará por defecto todos los elementos de la matriz?

EDITAR : si no, ¿existe una sintaxis que funcione en todas las matrices (incluidas las matrices de tamaño cero) para inicializar todos los elementos a su valor predeterminado?

EDITAR : en cppreference , la descripción del constructor predeterminado dice:

(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array 

entonces la respuesta puede ser sí. Pero me gustaría estar seguro de eso de acuerdo con el estándar o estándar futuro.

Vincent
fuente
No lo creo. Está declarado por defecto, por lo que es básicamente el equivalente a la T x[N]sintaxis.
Rapptz

Respuestas:

148

Por definición, la inicialización predeterminada es la inicialización que se produce cuando no se especifica ninguna otra inicialización; el lenguaje C ++ le garantiza que cualquier objeto para el que no proporcione un inicializador explícito se inicializará por defecto (C ++ 11 §8.5 / 11). Eso incluye objetos de tipo std::array<T, N>y T[N].

Tenga en cuenta que hay tipos para los que la inicialización predeterminada no tiene ningún efecto y deja indeterminado el valor del objeto: cualquier tipo que no sea de clase ni de matriz (§8.5 / 6). En consecuencia, una matriz de objetos inicializada por defecto con tales tipos tendrá un valor indeterminado, por ejemplo:

int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;

Tanto la matriz de estilo c como std::arrayse rellenan con números enteros de valor indeterminado, al igual que plain_inttiene valor indeterminado.

¿Existe una sintaxis que funcione en todas las matrices (incluidas las matrices de tamaño cero) para inicializar todos los elementos a su valor predeterminado?

Supongo que cuando dice "a su valor predeterminado" realmente quiere decir "inicializar todos los elementos a T{}". Eso no es inicialización predeterminada , es inicialización de valor (8.5 / 7). Puede solicitar la inicialización de valor con bastante facilidad en C ++ 11 dando a cada declaración un inicializador vacío:

int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};

Lo que inicializará con valor todos los elementos de la matriz a su vez, lo que dará como resultado plain_old_int, y todos los miembros de ambos tipos de matrices, que se inicialicen a cero.

Casey
fuente
¿Qué pasa si es un miembro de la clase: struct X {std :: array <int, 12> dozen; X (): docena () {} ¿Eso me da doce ceros?
gerardw
4
@gerardw Según el estándar, sí lo hace. Tenga cuidado con los errores en MSVC, no implementa correctamente algunos casos de inicialización de valores.
Casey
1
de hecho, boost lo dice y lo soluciona con su boost::value_initialized enlace, pero creo que VC12 (VS2013) tiene un soporte mucho mejor ahora.
v.oddou
1
Me hace desear que el comité cambie el estándar a la inicialización del valor predeterminado y el valor socavado a pedido. Es decir, estándar :: matriz <int, 12> = {estándar :: indeterminado}; o algo así
Viktor Sehr
En la práctica, ¿qué significa inicializar algo con un valor indeterminado? Cual es la alternativa?
Andrew
21

La inicialización predeterminada es un término del Estándar que potencialmente significa que no hay inicialización en absoluto, por lo que probablemente se refiera a la inicialización cero .

La descripción en cppreference.com es en realidad un poco engañosa. std::arrayes una clase agregada, y si el tipo de elemento es primitivo, es POD: "datos antiguos sin formato", con semántica que coincide estrechamente con el lenguaje C. El constructor implícitamente definido de std::array< int, N >es uno trivial que no hace absolutamente nada.

La sintaxis similar std::array< int, 3 >()o std::array< int, 3 > x{}que proporciona valores cero no lo hace invocando un constructor. Obtener ceros es parte de la inicialización de valor , especificado en C ++ 11 §8.5 / 8:

Inicializar con valor un objeto de tipo T significa:

- si T es un tipo de clase (posiblemente calificado por cv) sin un constructor predeterminado proporcionado por el usuario o eliminado, entonces el objeto se inicializa en cero ..., y si T tiene un constructor predeterminado no trivial, el objeto se inicializa por defecto;

std::arrayno tiene un constructor predeterminado proporcionado por el usuario, por lo que se inicializa en cero. Tiene un constructor predeterminado definido implícitamente, pero es trivial, por lo que nunca se inicializa por defecto. (Pero esto no hace una diferencia ya que la inicialización trivial por definición no tiene ningún efecto en el tiempo de ejecución).

Si no es así, ¿existe una sintaxis que funcione en todas las matrices (incluidas las matrices de tamaño cero) para inicializar todos los elementos a su valor predeterminado?

Los arreglos de estilo C y std::arrayambos son agregados, y la forma de inicializar completamente a cero cualquier agregado es con la sintaxis = {}. Esto funciona desde C ++ 98. Tenga en cuenta que las matrices de estilo C no pueden tener una extensión cero y que sizeof (std::array< X, 0 >)no es cero.

Potatoswatter
fuente
6

Ambos T x[N];y por std::array<T, N> x;defecto inicializan cada elemento de la matriz.

Por ejemplo, si T = std::string, cada elemento será una cadena vacía. Si Tes una clase sin un constructor predeterminado, ambos fallarán al compilar. Si T = int, cada elemento tendrá un valor indeterminado (a menos que esa declaración esté en el ámbito del espacio de nombres)

Cubbi
fuente
0

En primer lugar, T x [N] inicializa los elementos por defecto, aunque la inicialización por defecto de un tipo escalar T en realidad no hace nada. Lo anterior también es válido para std :: array x. Creo que lo que necesita es la inicialización de la lista.

Lingxi
fuente