std::array
es muy superior a las matrices C. E incluso si quiero interoperar con código heredado, puedo usar std::array::data()
. ¿Hay alguna razón por la que alguna vez quisiera una matriz de la vieja escuela?
std::array
es muy superior a las matrices C. E incluso si quiero interoperar con código heredado, puedo usar std::array::data()
. ¿Hay alguna razón por la que alguna vez quisiera una matriz de la vieja escuela?
Respuestas:
A menos que me haya perdido algo (no he seguido demasiado de cerca los cambios más recientes en el estándar), la mayoría de los usos de las matrices de estilo C aún permanecen. std::array
permite la inicialización estática, pero aún así no contará los inicializadores por usted. Y dado que el único uso real de las matrices de estilo C antes std::array
era para tablas inicializadas estáticamente en la línea de:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
utilizando las funciones habituales begin
y de end
plantilla (adoptadas en C ++ 11) para iterar sobre ellas. Sin mencionar el tamaño, que el compilador determina a partir del número de inicializadores.
EDITAR: Otra cosa que olvidé: los literales de cadena siguen siendo matrices de estilo C; es decir, con tipo char[]
. No creo que nadie excluya el uso de cadenas literales solo porque lo hemos hecho std::array
.
const char[]
No. Para, eh, decirlo sin rodeos. Y en 30 caracteres.
Por supuesto, necesita arreglos C para implementar std::array
, pero esa no es realmente una razón por la que un usuario alguna vez querría arreglos C. Además, no, std::array
no es menos eficaz que una matriz C y tiene una opción para un acceso con límites comprobados. Y finalmente, es completamente razonable que cualquier programa de C ++ dependa de la biblioteca estándar, ese es el punto de que sea estándar, y si no tiene acceso a una biblioteca estándar, entonces su compilador no es conforme y el La pregunta está etiquetada como "C ++", no "C ++ y esas cosas que no son C ++ que pierden la mitad de la especificación porque lo consideran inapropiado".
std::array
en una implementación independiente de C ++ 11.
Parece que usar matrices multidimensionales es más fácil con matrices C que std::array
. Por ejemplo,
char c_arr[5][6][7];
Opuesto a
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
También debido a la propiedad de decaimiento automático de las matrices de C, c_arr[i]
en el ejemplo anterior decaerá a un puntero y solo necesita pasar las dimensiones restantes como dos parámetros más. Mi punto es que c_arr
no es caro copiar. Sin embargo, cpp_arr[i]
será muy costoso copiarlo.
array
a una función sin perder dimensiones. Y si lo pasa a una plantilla de función, esa función podría deducir tanto la dimensión como el tamaño de cada dimensión, o solo una de las dos. Esto podría ser interesante para las bibliotecas de plantillas científicas que trabajan principalmente en dimensiones arbitrarias.
template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
debería resolver cualquiera de esos problemas.
c_arr
es muy caro de copiar! Debe proporcionar el código para hacerlo usted mismo. El puntero al que decaerá es un equivalente más cercano a una referencia que a una copia y puede usar std::array
para pasar una referencia si eso es lo que desea.
std::size_t
lugar de int
? perdón por ser quisquilloso, pero esto lo haría universal.
size_t
si quieres, aunque no puedo imaginar que haya muchos escenarios en los que se necesiten matrices con más de 4 mil millones de filas o columnas.
Como dijo Sumant, las matrices multidimensionales son mucho más fáciles de usar con matrices C integradas que con std::array
.
Cuando está anidado, std::array
puede resultar muy difícil de leer e innecesariamente detallado.
Por ejemplo:
std::array<std::array<int, 3>, 3> arr1;
comparado con
char c_arr[3][3];
Además, tenga en cuenta que begin()
, end()
y size()
todos devuelven valores sin sentido cuando anida std::array
.
Por estas razones, he creado mis propios contenedores de matrices multidimensionales de tamaño fijo array_2d
y array_3d
. Son análogos a std::array
pero para matrices multidimensionales de 2 y 3 dimensiones. Son más seguras y no tienen peor rendimiento que las matrices multidimensionales integradas. No incluí un contenedor para matrices multidimensionales con dimensiones superiores a 3, ya que son poco comunes. En C ++ 0x se podría crear una versión de plantilla variada que admita un número arbitrario de dimensiones.
Un ejemplo de la variante bidimensional:
//Create an array 3 x 5 (Notice the extra pair of braces)
fsma::array_2d <double, 3, 5> my2darr = {{
{ 32.19, 47.29, 31.99, 19.11, 11.19},
{ 11.29, 22.49, 33.47, 17.29, 5.01 },
{ 41.97, 22.09, 9.76, 22.55, 6.22 }
}};
La documentación completa está disponible aquí:
http://fsma.googlecode.com/files/fsma.html
Puede descargar la biblioteca aquí:
arr[x][y]
, no se puede saber si arr
es una matriz de matrices, una matriz de punteros, un puntero a una matriz o un puntero a un puntero; todas las implementaciones son legítimas, dependiendo de sus necesidades. Y probablemente la mayoría de los casos de uso del mundo real para matrices multidimensionales requieren que el tamaño se determine en tiempo de ejecución.
Las matrices de estilo C que están disponibles en C ++ son en realidad mucho menos versátiles que las matrices C reales. La diferencia es que en C, los tipos de matriz pueden tener tamaños de tiempo de ejecución . El siguiente es código C válido, pero no se puede expresar con matrices de estilo C ++ ni con los array<>
tipos C ++ :
void foo(int bar) {
double tempArray[bar];
//Do something with the bar elements in tempArray.
}
En C ++, tendría que asignar la matriz temporal en el montón:
void foo(int bar) {
double* tempArray = new double[bar];
//Do something with the bar elements behind tempArray.
delete[] tempArray;
}
Esto no se puede lograr con std::array<>
, porque bar
no se conoce en tiempo de compilación, requiere el uso de matrices de estilo C en C ++ o de std::vector<>
.
Si bien el primer ejemplo podría expresarse con relativa facilidad en C ++ (aunque requiera new[]
y delete[]
), lo siguiente no se puede lograr en C ++ sin std::vector<>
:
void smoothImage(int width, int height, int (*pixels)[width]) {
int (*copy)[width] = malloc(height*sizeof(*copy));
memcpy(copy, pixels, height*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y][x] = //compute smoothed value based on data around copy[y][x]
}
}
free(copy);
}
El punto es que los punteros a los arreglos lineales int (*)[width]
no pueden usar un ancho de tiempo de ejecución en C ++, lo que hace que cualquier código de manipulación de imágenes sea mucho más complicado en C ++ que en C.Una implementación típica de C ++ del ejemplo de manipulación de imágenes se vería así:
void smoothImage(int width, int height, int* pixels) {
int* copy = new int[height*width];
memcpy(copy, pixels, height*width*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
}
}
delete[] copy;
}
Este código hace precisamente los mismos cálculos que el código C anterior, pero necesita realizar el cálculo del índice a mano dondequiera que se utilicen los índices . Para el caso 2D, esto sigue siendo factible (aunque ofrece muchas oportunidades para hacer un cálculo incorrecto del índice). Sin embargo, se vuelve realmente desagradable en el caso de 3D.
Me gusta escribir código en C ++. Pero siempre que necesito manipular datos multidimensionales, realmente me pregunto si debería mover esa parte del código a C.
gcc
por ejemplo). C11 ha hecho que algunas cosas interesantes sean opcionales, y no creo que sea porque quieran prohibir la función. Tiendo a verlo como una señal de que querían bajar el nivel para escribir un compilador totalmente compatible con el estándar: los VLA son una bestia bastante difícil de implementar, y mucho código puede prescindir, por lo que tiene sentido para un nuevo compilador en algunos nuevos plataforma para no tener que implementar VLA de inmediato.
Puede ser std::array
que no sea lento. Pero hice algunas evaluaciones comparativas usando simple store y leí desde std :: array; Vea los resultados de referencia a continuación (en W8.1, VS2013 Update 4):
ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;
test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305
Según las marcas negativas, el código que utilicé está en el pastebin ( enlace )
El código de la clase de referencia está aquí ;
No sé mucho sobre evaluaciones comparativas ... Mi código puede tener fallas
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
ahora. Realmente necesita saltar a través de aros para asegurarse de que el código que está midiendo es el código que desea medir.
std::array
std::array
será menos eficiente que una matriz C.
at()
, no está dentro operator[]
, como std::vector
. No hay disminución del rendimiento ni exceso de código std::array
, el compilador está diseñado para optimizar este tipo de cosas. Y, por supuesto, la adición de la función comprobada es una excelente herramienta de depuración y una gran ventaja. @Lou Franco: Todo el código C ++ puede depender de la biblioteca estándar, para eso es. @Earlz: Si no tiene STL disponible, entonces no es C ++, y eso es todo.
std::array
sea más grande que el uso de matriz C equivalente.