2010-12-01 25 views
6

Estoy teniendo un momento difícil para familiarizarme con la forma de inicializar un vector de vectores.Vector de Inicialización de Vector

typedef vector < vector < vector < vector < float>>> DataContainer;

Quiero que esto se ajusta a

level_1 (2 elements/vectors) 
    level_2 (7 elements/vectors) 
     level_3 (480 elements/vectors) 
     level_4 (31 elements of float) 

Dirigiéndose a los elementos no es la cuestión. Eso debería ser tan simple como algo parecido a

dc[0][1][2][3]; 

El problema es que necesito a llenarlo con los datos procedentes de fuera de servicio desde un archivo de tal manera que los elementos sucesivos deben ser colocados algo así como

dc[0][3][230][22]; 
dc[1][3][110][6]; //...etc 

Así que necesito inicializar la V de V de antemano.

¿Estoy psicológicamente a mí mismo o esto es tan simple como

for 0..1 
    for 0..6 
     for 0..479 
      for 0..30 
       dc[i][j][k][l] = 0.0; 

No parece como que debería funcionar. De alguna manera, los vectores de nivel superior deben inicializarse primero.

Cualquier ayuda apreciada. Estoy seguro de que esto debe ser más simple de lo que imagino.

Respuesta

16
  • favor no utilizan vectores anidados si el tamaño de su almacenamiento de se conoce de antemano, es decir, hay una razón específica por qué, por ejemplo, el primer índice debe ser del tamaño 6 y nunca cambiará. Solo use una matriz simple. Mejor aún, use boost::array. De esta forma, obtienes todos los beneficios de tener una matriz simple (ahorra una gran cantidad de espacio cuando utilizas varias dimensiones) y los beneficios de tener una instanciación real de objetos.

  • favor no utilizan vectores anidados si su almacenamiento debe ser rectangular, es decir, es posible cambiar el tamaño de una o más de las dimensiones, pero cada "fila" deben tener la misma longitud en algún momento. Use boost::multi_array. De esta manera, se documentan "este almacenamiento es rectangular", guardar grandes cantidades de espacio y aún así obtener la capacidad de cambiar el tamaño, beneficios de tener un objeto real, etc.

Lo que pasa es que std::vector (una) está destinado a ser redimensionable y (b) no se preocupa por su contenido en lo más mínimo, siempre y cuando sean del tipo correcto. Esto significa que si tiene un vector<vector<int> >, entonces todos los "vectores de fila" deben mantener su propia información separada de contabilidad sobre cuánto tiempo son, incluso si desea exigir que todos tengan la misma longitud.También significa que todos manejan asignaciones de memoria separadas, lo que perjudica el rendimiento (comportamiento de caché) y desperdicia aún más espacio debido a la forma en que std::vector se reasigna. boost::multi_array está diseñado con la expectativa de que es posible que desee cambiar el tamaño de la misma, pero no se cambiará de tamaño constantemente agregando elementos (filas, para una matriz/caras bidimensionales, una matriz tridimensional/etc.) hasta el final . std::vector está diseñado para (potencialmente) perder espacio para asegurarse de que la operación no sea lenta. boost::multi_array está diseñado para ahorrar espacio y mantener todo ordenado en la memoria.

Dicho:

Sí, usted tiene que hacer algo antes de que pueda índice en el vector. std::vector no causará mágicamente que los índices aparezcan porque usted quiere almacenar algo allí. Sin embargo, esto es fácil de tratar:

Primero puede inicializar por defecto el vector con la cantidad apropiada de ceros y luego reemplazarlos, utilizando el constructor (size_t n, const T& value = T()). Es decir,

std::vector<int> foo(10); // makes a vector of 10 ints, each of which is 0 

porque un int "default-construida" tiene el valor 0.

En su caso, tenemos que especificar el tamaño de cada dimensión, mediante la creación de sub-vectores que son de la tamaño apropiado y dejar que el constructor los copie. Esto se parece a:

typedef vector<float> d1; 
typedef vector<d1> d2; 
typedef vector<d2> d3; 
typedef vector<d3> d4; 
d4 result(2, d3(7, d2(480, d1(31)))); 

Es decir, un anónimo d1 se construye de tamaño 31, que se utiliza para inicializar el valor por defecto d2, que se utiliza para inicializar el valor por defecto d3, que se utiliza para inicializar result.

Existen otros enfoques, pero son mucho más torpes si solo quieres comenzar un montón de ceros. Si usted va a leer todo el conjunto de datos de un archivo, sin embargo:

  • Puede utilizar .push_back() para anexar a un vector. Haga un d1 vacío justo antes del bucle más interno, en el que repetidamente .push_back() para llenarlo. Justo después del bucle, .push_back() el resultado en el d2 que creó justo antes del siguiente bucle más interno, y así sucesivamente.

  • Puede cambiar el tamaño de un vector de antemano con .resize(), y luego indexarlo normalmente (hasta la cantidad que cambió el tamaño).

+0

Construcción ordenada allí. Le daré un impulso a multi_array. Gracias por la respuesta en profundidad. – ValenceElectron

+2

En el nuevo estándar de C++, 'std :: array' proporciona la funcionalidad de' boost :: array' en la biblioteca estándar. –

0

Es probable que tenga que establecer un tamaño o reserva de memoria

Podría hacer una for-each o una anidada para que llame

myVector.resize(x); //or size 

en cada nivel.

+0

.size() comprueba el tamaño actual del vector. Quieres .resize(). –

1

EDIT: Tengo que admitir que este código no es elegante. Me gusta la respuesta de @Karl, que es la forma correcta de hacerlo.

Este código está compilado y probado. Imprimió 208320 ceros que se espera (2 * 7 * 480 * 31)

#include <iostream> 
#include <vector> 

using namespace std; 

typedef vector< vector < vector < vector<float> > > > DataContainer; 

int main() 
{ 
    const int LEVEL1_SIZE = 2; 
    const int LEVEL2_SIZE = 7; 
    const int LEVEL3_SIZE = 480; 
    const int LEVEL4_SIZE = 31; 

    DataContainer dc; 

    dc.resize(LEVEL1_SIZE); 
    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     dc[i].resize(LEVEL2_SIZE); 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      dc[i][j].resize(LEVEL3_SIZE); 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       dc[i][j][k].resize(LEVEL4_SIZE); 
      } 
     } 
    } 

    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       for (int l = 0; l < LEVEL4_SIZE; ++l) { 
        dc[i][j][k][l] = 0.0; 
       } 
      } 
     } 
    } 

    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       for (int l = 0; l < LEVEL4_SIZE; ++l) { 
        cout << dc[i][j][k][l] << " "; 
       } 
      } 
     } 
    } 

    cout << endl; 
    return 0; 
} 
+0

Esto es exactamente lo que me di cuenta unos 30 segundos después de la publicación. Debería funcionar, pero el impulso de Karl multi_array parece ser una mejor opción. – ValenceElectron