2010-12-01 37 views
6

J'ai du mal à faire tourner ma tête autour de l'initialisation d'un vecteur de vecteurs.Vecteur d'initialisation de vecteur

typedef vecteur < vecteur < vecteur < vecteur < float>>> DataContainer;

Je veux que cela conforme à

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

Aborder les éléments n'est pas la question. Cela devrait être aussi simple que quelque chose comme

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

Le problème est que je dois le remplir avec des données venant de l'ordre d'un fichier tel que les éléments successifs doivent être placés quelque chose comme

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

J'ai donc besoin d'initialiser le V de V au préalable.

Suis-je moi-même psyching ou est-ce aussi simple que

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

Il ne semble pas comme ça devrait fonctionner. D'une certaine manière, les vecteurs de niveau supérieur doivent être initialisés en premier.

Toute aide appréciée. Je suis sûr que cela doit être plus simple que je ne l'imagine.

Répondre

16
  • S'il vous plaît ne pas utiliser des vecteurs imbriqués si la taille de votre stockage est connu à l'avance, à savoir il y a une raison spécifique pourquoi par exemple le premier index doit être de taille 6, et ne changera jamais. Utilisez simplement un tableau simple. Mieux encore, utilisez boost::array. De cette façon, vous bénéficiez de tous les avantages d'un tableau simple (économisez énormément d'espace lorsque vous utilisez plusieurs dimensions) et des avantages d'une véritable instanciation d'objet.

  • S'il vous plaît ne pas utiliser des vecteurs imbriqués si votre stockage doit être rectangulaire, à savoir que vous pouvez redimensionner une ou plusieurs des dimensions, mais chaque « ligne » doit être la même longueur à un moment donné. Utilisez boost::multi_array. De cette façon, vous documentez « ce stockage est rectangulaire », sauf d'énormes quantités d'espace et encore obtenir la possibilité de redimensionner, les avantages d'avoir un objet réel, etc.

La chose au sujet std::vector est qu'il (a) est destiné à être redimensionnable et (b) ne se soucie pas de son contenu le moins du monde, du moment qu'ils sont du type correct. Cela signifie que si vous avez un vector<vector<int> >, alors tous les «vecteurs de lignes» doivent conserver leurs propres informations de tenue de livres séparées sur leur durée de vie - même si vous voulez faire valoir qu'ils ont tous la même longueur.Cela signifie également qu'ils gèrent tous des allocations de mémoire distinctes, ce qui nuit aux performances (comportement du cache) et gaspille encore plus d'espace en raison de la façon dont les ressources sont réparties. boost::multi_array est conçu dans l'espoir que vous voudrez peut-être le redimensionner, mais ne le redimensionnera pas constamment en ajoutant des éléments (lignes, pour un tableau bidimensionnel/faces, pour un tableau tridimensionnel/etc.) jusqu'à la fin . std::vector est conçu pour (potentiellement) gaspiller de l'espace pour s'assurer que l'opération n'est pas lente. boost::multi_array est conçu pour économiser de l'espace et garder tout bien organisé en mémoire.

Cela dit:

Oui, vous avez besoin de faire quelque chose avant que vous pouvez indexer dans le vecteur. std::vector ne fera pas apparaître les index par magie parce que vous voulez y stocker quelque chose. Cependant, ceci est facile à gérer:

Vous pouvez initialiser le vecteur avec la quantité appropriée de zéros en premier, puis les remplacer en utilisant le constructeur (size_t n, const T& value = T()). C'est,

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

parce qu'un « défaut construit » int a la valeur 0.

Dans votre cas, il faut spécifier la taille de chaque dimension, en créant des sous-vecteurs qui sont des taille appropriée et en laissant le constructeur les copier. Cela ressemble à:

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)))); 

C'est un d1 sans nom est construit de la taille 31, qui est utilisé pour initialiser la valeur par défaut d2, qui est utilisé pour initialiser la valeur par défaut d3, qui est utilisé pour initialiser result.

Il existe d'autres approches, mais elles sont beaucoup plus maladroites si vous voulez juste démarrer un groupe de zéros. Si vous allez lire l'ensemble des données d'un fichier, si:

  • Vous pouvez utiliser .push_back() à ajouter à un vecteur. Faites un vide d1 juste avant la boucle la plus interne, dans lequel vous .push_back() à plusieurs reprises pour le remplir. Juste après la boucle, vous obtenez le résultat sur le d2 que vous avez créé juste avant la boucle la plus proche, et ainsi de suite.

  • Vous pouvez redimensionner un vecteur au préalable avec .resize(), puis y indexer normalement (jusqu'à la taille à laquelle vous l'avez redimensionné).

+0

Construction soignée là-bas. Je vais donner un coup de boost à multi_array. Merci pour la réponse en profondeur. – ValenceElectron

+2

Dans la nouvelle norme C++, la fonctionnalité de 'boost :: array' est fournie par' std :: array' dans la bibliothèque standard. –

0

Vous auriez probablement définir une taille ou une réserve mémoire

Pourriez-vous faire pour-chacun ou un imbriquée pour appeler qui

myVector.resize(x); //or size 

à chaque niveau.

+0

.size() vérifie la taille actuelle du vecteur. Vous voulez .resize(). –

1

EDIT: Je reconnais que ce code n'est pas élégant. J'aime @Karl réponse qui est la bonne façon de procéder.

Ce code a été compilé et testé. Il a imprimé 208320 zéros ce qui est attendu (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

C'est exactement ce que j'ai réalisé environ 30 secondes après la publication. Ca devrait marcher mais le boost de Karl multi_array semble être un meilleur choix. – ValenceElectron