0
votes

Comment réserver un vecteur multidimensionnel sans augmenter la taille du vecteur?

J'ai des données qui sont N par 4 que je repousse les données comme suit.

vector<vector<int>> a;
a.resize(13000,vector<int>(4));

N serait inférieur à 13000. Afin d'éviter une réallocation inutile, je voudrais réserver 13000 par 4 espaces à l'avance.

Après avoir lu plusieurs articles connexes sur ce sujet (par exemple, Comment réserver un vecteur multidimensionnel? ) , Je sais que ce qui suit fera le travail. Mais j'aimerais le faire avec reserve () ou toute fonction similaire s'il y en a, pour pouvoir utiliser push_back().

vector<vector<int>> a(13000,vector<int>(4);

ou

vector<vector<int>> a;
for(some loop){
   ...
   a.push_back(vector<int>(4){val1,val2,val3,val4});
}

Comment puis-je simplement réserver de la mémoire sans augmenter la taille du vecteur?


0 commentaires

3 Réponses :


6
votes

Vous avez déjà répondu à votre propre question. Il existe une fonction vector :: reserve qui fait exactement ce que vous voulez.

vector<vector<int>> a;
a.reserve(N);
for(some loop){
   ...
   a.push_back(vector<int>(4){val1,val2,val3,val4});
}

Cela réservera de la mémoire pour s'adapter à N fois vector . Notez que la taille réelle du vector interne n'est pas pertinente à ce stade car les données d'un vecteur sont allouées ailleurs, seuls un pointeur et une certaine comptabilité sont stockés dans le std réel :: vector -class.


0 commentaires

6
votes

Si vos données sont garanties N x 4, vous ne voulez pas utiliser un std::vector> , mais plutôt quelque chose comme std :: vector > .

Pourquoi?

  • C'est le type le plus sémantiquement précis - std :: array est conçu pour des séquences contiguës de données de largeur fixe. (Cela ouvre également le potentiel pour plus d'optimisations de performances par le compilateur, bien que cela dépende exactement de ce que vous écrivez.)
  • Vos données seront disposées de manière contiguë en mémoire, plutôt que chacun des différents vecteurs allouant des emplacements de tas potentiellement disparates.

Cela dit, la réponse de @ pasbi est correcte: vous pouvez utiliser std :: vector :: reserve () pour allouer de l'espace pour votre vecteur externe avant d'insérer des éléments réels (à la fois pour les vecteurs-de-vecteurs et pour les vecteurs-de-tableaux). De plus, plus tard, vous pouvez utiliser std :: vector :: shrink_to_fit () si vous avez fini par en insérer beaucoup moins que ce que vous aviez prévu.

Enfin, une autre option consiste à utiliser un gsl :: multispan et un pré- allouez-lui de la mémoire (GSL est la Library ).


1 commentaires

Parfait! Merci beaucoup!



1
votes

Remarque: cette réponse n'est ici que par souci d'exhaustivité au cas où vous auriez un problème similaire avec une taille inconnue; garder un std :: vector > dans votre cas fera parfaitement l'affaire.

Pour reprendre la réponse d'einpoklum, et au cas où vous ne l'auriez pas trouvé ceci plus tôt, c'est presque toujours une mauvaise idée d'avoir des std :: vectors imbriqués, à cause de la disposition de la mémoire dont il a parlé. Chaque vecteur interne allouera son propre bloc de données, qui ne sera pas (nécessairement) contigu aux autres, ce qui produira des erreurs de cache.

De préférence, soit:

  • Comme déjà dit, utilisez un std :: array si vous avez une quantité fixe et connue d'éléments par vecteur;
  • Ou aplatissez votre structure de données en ayant un seul std::vector de taille N x M.
// Before:
int& element = vec[nIndex][mIndex];

// After:
int& element = vec[mIndex * 13000 + nIndex]; // Still assuming N = 13000

Ensuite, vous pouvez y accéder comme suit:

// Assuming N = 13000, M = 4

std::vector<int> vec;
vec.reserve(13000 * 4);


1 commentaires

Merci beaucoup! Je pensais qu'il serait alloué dans un espace contigu après l'aplatissement si je le déclare comme vector > a; et réserve de l'espace à l'avance. Mais c'était une idée stupide de réfléchir à la signification du vecteur. :)