En C ++, ¿cuál es el punto de std :: array si el tamaño debe determinarse en tiempo de compilación?

2020-02-15 c++ c++11 stdarray

Disculpe mi ignorancia, me parece que std::array está destinado a ser un reemplazo de STL para sus arreglos regulares. Pero debido a que el tamaño de la matriz debe pasarse como un parámetro de plantilla, nos impide crear std::array con un tamaño conocido solo en tiempo de ejecución.

std::array<char,3> nums {1,2,3}; // Works.

constexpr size_t size = 3;
std::array<char,size> nums {1,2,3}; // Works.

const buf_size = GetSize();
std::array<char, buf_size> nums; // Doesn't work.

Supongo que un caso de uso muy importante para una matriz en C ++ es crear una estructura de datos de tamaño fijo basada en entradas de tiempo de ejecución (por ejemplo, asignar un búfer para leer archivos).

Las soluciones que uso para esto son:

// Create a array pointer for on-the-spot usecases like reading from a file.
char *data = new char[size];
...
delete[] data;

o:

// Use unique_ptr as a class member and I don't want to manage the memory myself.
std::unique_ptr<char[]> myarr_ = std::unique_ptr<char[]>(new char[size]);

Si no me importa el tamaño fijo, soy consciente de que puedo usar std::vector<char> con el tamaño predefinido de la siguiente manera:

std::vector<char> my_buf (buf_size);

¿Por qué los diseñadores de std::array decidieron ignorar este caso de uso? Quizás no entiendo el caso de uso real de std::array .

EDITAR: Supongo que otra forma de formular mi pregunta también podría ser: ¿por qué los diseñadores decidieron que el tamaño se pasara como un parámetro de plantilla y no como un parámetro de constructor? ¿Optar por este último habría dificultado proporcionar la funcionalidad que std::array tiene actualmente? A mí me parece una elección de diseño deliberada y no entiendo por qué.

Answers

std::array es un reemplazo para las matrices de estilo C.

Los estándares C ++ no permiten que se declaren matrices de estilo C sin tamaños definidos en tiempo de compilación.

Facilidad de programación

std::array facilita varias interfaces y modismos beneficiosos que se utilizan en std::vector . Con matrices de estilo C normales, uno no puede tener .size() (sin sizeof hack), .at() (excepción para fuera de rango), front()/back() , iteradores, etc. Todo tiene que ser codificado a mano.

Muchos programadores pueden elegir std::vector incluso para compilar matrices de tamaño conocido, simplemente porque quieren utilizar las metodologías de programación anteriores. Pero eso quita el rendimiento disponible con matrices de tamaño fijo en tiempo de compilación.
Por lo tanto, los creadores de bibliotecas proporcionaron std::array para desalentar los arreglos de estilo C y evitar std::vector s cuando se conoce el tamaño en el momento de la compilación.

Las dos razones principales que entiendo son:

  • std::array implementa las interfaces de STL para los tipos de colección, permitiendo que un std::array se pase como está a las funciones y métodos que aceptan cualquier iterador STL.
  • Para evitar la caída del puntero de la matriz ... (abajo)

... esta es la preservación de la información de tipo a través de límites de función / método porque evita la Decadencia del Puntero de Array .

Dada una matriz C / C ++ desnuda, puede pasarla a otra función como argumento de parámetro de 4 maneras:

void by_value1   ( const T* array )
void by_value2   ( const T array[] )
void by_pointer  ( const T (*array)[U] )
void by_reference( const T (&array)[U] )
  • by_value1 y by_value2 son semánticamente idénticos y causan la caída del puntero porque la función de recepción no conoce el sizeof la matriz.
  • by_pointer y by_reference requieren que U una constante de tiempo de compilación conocida, pero conservan el sizeof información.

Entonces, si evita la descomposición de la matriz mediante by_pointer o by_reference , ahora tiene un problema de mantenimiento cada vez que cambia el tamaño de la matriz, debe actualizar manualmente todos los sitios de llamadas que tienen ese tamaño en U

Al usar std::array se ocupa de usted haciendo que las funciones de template funciones donde U es un parámetro (concedido, aún podría usar las técnicas by_pointer y by_reference pero con una sintaxis más desordenada).

... entonces std::array agrega una quinta forma :

template<typename T, size_t N>
void by_stdarray( const std::array<T,N>& array )

Related