2010-12-12 24 views
208

¿Cuál es la diferencia entre un std::vector y un std::array en C++? ¿Cuándo se debe preferir uno a otro? ¿Cuáles son los pros y los contras de cada uno? Todo lo que hace mi libro de texto es una lista de cómo son iguales.std :: vector versus std :: array en C++

+1

Estoy buscando una comparación de 'std :: vector' contra' std :: array' y cómo los términos son diferentes. – Zud

+0

Zud, 'std :: array' no es lo mismo que una matriz C++. 'std :: array' es un contenedor muy fino alrededor de las matrices C++, con el objetivo principal de ocultar el puntero del usuario de la clase. Actualizaré mi respuesta. – ClosureCowboy

+0

Actualicé el título y el texto de la pregunta para reflejar su aclaración. –

Respuesta

235

std::vector es una clase de plantilla que encapsulan una matriz dinámica , almacenada en el montón, que crece y se contrae de forma automática si se añaden o eliminan elementos. Proporciona todos los enganches (begin(), end(), iteradores, etc.) que lo hacen funcionar bien con el resto del STL. También tiene varios métodos útiles que le permiten realizar operaciones que en una matriz normal serían engorrosas, como p. Ej. insertando elementos en el medio de un vector (maneja todo el trabajo de mover los siguientes elementos detrás de las escenas).

Dado que almacena los elementos en la memoria asignada en el montón, tiene cierta sobrecarga con respecto a las matrices estáticas.

std::array es una clase de plantilla que encapsulan una matriz estática de tamaño, almacenada dentro del objeto en sí mismo, lo que significa que, si se instancia la clase en la pila, la matriz en sí será en la pila. Su tamaño debe conocerse en tiempo de compilación (se pasa como un parámetro de plantilla) y no puede crecer ni reducirse.

Es más limitado que std::vector, pero a menudo es más eficiente, especialmente para tamaños pequeños, porque en la práctica es principalmente un envoltorio liviano alrededor de una matriz estilo C. Sin embargo, es más seguro, ya que la conversión implícita a puntero está deshabilitada y proporciona gran parte de la funcionalidad relacionada con STL de std::vector y de los demás contenedores, por lo que puede usarla fácilmente con los algoritmos STL & co. De todos modos, para la misma limitación de tamaño fijo, es mucho menos flexible que std::vector.

Para una introducción a std::array, eche un vistazo a this article; para una introducción rápida al std::vector y a las operaciones que son posibles en él, es posible que desee consultar su documentation.


  1. En realidad, creo que en la norma que se describen en términos de máxima complejidad de las diferentes operaciones (por ejemplo, acceso aleatorio en un tiempo constante, iteración sobre todos los elementos en el tiempo lineal, añadir y eliminación de elementos al final en tiempo amortizado constante, etc.), pero AFAIK no hay otro método para cumplir tales requisitos además de usar una matriz dinámica. Según lo establecido por @Lucretiel, el estándar en realidad requiere que los elementos se almacenen contiguamente, por lo que es una matriz dinámica, almacenada donde lo ubica el asignador asociado.
+5

En cuanto a su nota al pie: Si bien es cierto, el estándar también garantiza que la aritmética del puntero en los elementos internos funciona, lo que significa que tiene que ser una matriz: & vec [9] - & vec [3] == 6 es verdadero. – Lucretiel

+5

Estoy bastante seguro de que ese vector no se contrae automáticamente, pero desde C++ 11 puede llamar a shrink_to_fit. – Dino

+0

Estoy totalmente confundido con el término _static array_ y no estoy seguro de cuál es la terminología correcta. Quiere decir una matriz de tamaño estático y no una matriz de variable estática (una que usa almacenamiento estático). https://stackoverflow.com/questions/2672085/c-static-array-vs-dynamic-array/26466627#26466627. ¿Cuál es la terminología correcta? ¿Es static array un término descuidado para una matriz con un tamaño fijo? –

-13

Un vector es una clase contenedor mientras que una matriz es una memoria asignada.

+12

Su respuesta parece abordar 'std :: vector ' contra 'T []', pero la pregunta es sobre 'std :: vector ' contra 'std :: array '. –

13

Utilización de la clase std::vector<T>:

  • ... es tan rápido como utilizando matrices incorporadas, suponiendo que están haciendo solamente las cosas matrices incorporadas permiten que hagas (leer y escribir en elementos existentes).

  • ... cambia el tamaño automáticamente cuando se insertan nuevos elementos.

  • ... le permite insertar nuevos elementos al principio o en medio del vector, de forma automática "desplazar" el resto de los elementos de "arriba" (¿tiene sentido?). Le permite eliminar elementos en cualquier parte del std::vector, también, desplazando automáticamente el resto de los elementos hacia abajo.

  • ... le permite realizar una lectura verificada por rango con el método at() (siempre puede usar los indexadores [] si no desea que se realice esta verificación).

Hay dos tres principales advertencias para el uso de std::vector<T>:

  1. No tiene acceso fiable al puntero subyacente, que puede ser un problema si se trata de funciones de terceros que exigen la dirección de una matriz.

  2. La clase std::vector<bool> es tonta. Se implementa como un bitfield condensado, no como una matriz. ¡Evítalo si quieres una matriz de bool s!

  3. Durante el uso, std::vector<T> s van a ser un poco más grandes que una matriz C++ con la misma cantidad de elementos. Esto se debe a que necesitan realizar un seguimiento de una pequeña cantidad de otra información, como su tamaño actual, y porque cada vez que std::vector<T> cambian de tamaño, reservan más espacio que el que necesitan. Esto es para evitar que tengan que cambiar el tamaño cada vez que se inserta un nuevo elemento. Este comportamiento se puede cambiar proporcionando un allocator personalizado, ¡pero nunca sentí la necesidad de hacerlo!


Editar: Después de leer la respuesta de Zud a la pregunta, me sentí que debería añadir:

La clase std::array<T> no es lo mismo que una matriz C++. std::array<T> es una envoltura muy delgada alrededor de las matrices de C++, con el objetivo principal de ocultar el puntero del usuario de la clase (en C++, las matrices se moldean implícitamente como punteros, a menudo con un efecto desalentador). La clase std::array<T> también almacena su tamaño (longitud), que puede ser muy útil.

+4

Es 'tan rápido' como usar una matriz incorporada asignada dinámicamente. Por otro lado, usar una matriz automática podría tener un rendimiento considerablemente diferente (y no solo durante la asignación, debido a los efectos de localidad). –

+2

Para no-bool vectores en C++ 11 y posteriores, puede llamar a 'data()' en un 'std :: vector ' para obtener el puntero subyacente. También puede simplemente tomar la dirección del elemento 0 (garantizado para trabajar con C++ 11, probablemente funcione con versiones anteriores). – Matt

-12

Una de las ventajas que los vectores tienen más de matrices es que es posible encontrar la tamaño actual de un vector usando vector_name.size().

Como se puede imaginar, esto puede ser bastante útil en una variedad de situaciones, donde puede obtener fácilmente una cantidad de elementos en array_list.

+10

También puede hacer eso con std :: array – Gerard

10

Para enfatizar un punto hecho por @MatteoItalia, la diferencia de eficiencia es donde se almacenan los datos. La memoria de pila (requerida con vector) requiere una llamada al sistema para asignar memoria y esto puede ser costoso si está contando ciclos. La memoria de pila (posible para array) es virtualmente "cero-overhead" en términos de tiempo, porque la memoria se asigna simplemente ajustando el puntero de la pila y se realiza solo una vez al ingresar a una función. La pila también evita la fragmentación de la memoria.Para estar seguro, std::array no siempre estará en la pila; depende de dónde lo asigne, pero todavía implicará una asignación de memoria menos del montón en comparación con el vector. Si usted tiene un pequeño "matriz"

  • (menos de 100 elementos dicen) - (una pila típica es de aproximadamente 8 MB, así que no se asigne más de unos pocos KB en la pila o menos si su código es recursivo)
  • el tamaño será fijado
  • la vida útil está en el ámbito de la función (o es un valor de miembro con el mismo tiempo de vida como la clase padre)
  • ciclos usted está contando,

definitivamente el uso de una std::array en un vector. Si alguno de esos requisitos no es cierto, utilice un std::vector.

+3

Buena respuesta. "Para estar seguro, std :: array no siempre estará en la pila; depende de dónde lo asigne "Entonces, ¿cómo podría crear un std :: array que no esté en la pila con una gran cantidad de elementos? – Trilarion

+3

@Trilarion use' new std :: array' o conviértalo en miembro de una clase que usted use 'new' para asignar. –

+0

Entonces, esto significa 'new std :: array' todavia espera conocer su tamano en tiempo de compilacion y no puede cambiar su tamano pero todavia vive en el montículo? – Trilarion

6

Si está considerando utilizar matrices multidimensionales, existe una diferencia adicional entre std :: array y std :: vector. Una matriz std :: multidimensional tendrá los elementos empaquetados en la memoria en todas las dimensiones, al igual que una matriz de estilo c. Un std :: vector multidimensional no se embalará en todas las dimensiones.

Dadas las siguientes declaraciones:

int cConc[3][5]; 
std::array<std::array<int, 5>, 3> aConc; 
int **ptrConc;  // initialized to [3][5] via new and destructed via delete 
std::vector<std::vector<int>> vConc; // initialized to [3][5] 

Un puntero al primer elemento de la matriz c-estilo (cConc) o el std :: array (aConc) se pueden repetir a través de toda la matriz mediante la adición de 1 a cada elemento precedente. Están apretados.

Un puntero al primer elemento de la matriz de vectores (vConc) o la matriz de punteros (ptrConc) solo se puede iterar a través de los primeros 5 (en este caso) elementos, y luego hay 12 bytes (en mi sistema) de sobrecarga para el siguiente vector.

Esto significa que una matriz std :: vector> inicializada como una matriz [3] [1000] será mucho más pequeña en memoria que una inicializada como una matriz [1000] [3], y ambas serán más grandes en la memoria que una matriz estándar: asignada de cualquier manera.

Esto también significa que no puede simplemente pasar una matriz multidimensional de vector (o puntero) a, por ejemplo, OpenGL sin tener en cuenta la sobrecarga de memoria, sino que puede pasar ingenuamente una matriz std :: multidimensional a OpenGL y tenerla rutina de ejercicio.