103 votes

std::vector::resize() vs. std::vector::reserve()

Il y a un fil dans la section des commentaires dans ce poste sur l'utilisation std::vector::reserve() vs. std::vector::resize() .

Voici le code original :

void MyClass::my_method()
{
    my_member.reserve(n_dim);
    for(int k = 0 ; k < n_dim ; k++ )
         my_member[k] = k ;
}

Je crois que pour écrire des éléments dans le vector la chose correcte à faire est d'appeler std::vector::resize() pas std::vector::reserve() .

En fait, le code de test suivant "plante" dans les constructions de débogage dans VS2010 SP1 :

#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    v.reserve(10);
    v[5] = 2;

    return 0;
}

Ai-je raison, ou ai-je tort ? Et VS2010 SP1 est-il bon ou mauvais ?

143voto

CashCow Points 18388

Il y a deux méthodes différentes pour une raison :

std::vector::reserve allouera la mémoire mais ne redimensionnera pas votre vecteur, qui aura une taille logique identique à celle qu'il avait auparavant.

std::vector::resize modifiera en fait la taille de votre vecteur et remplira tout espace avec des objets dans leur état par défaut. Si ce sont des ints, ils seront tous à zéro.

Après la réserve, dans votre cas, vous aurez besoin de beaucoup de push_backs pour écrire dans l'élément 5. Si vous ne souhaitez pas faire cela, alors dans votre cas, vous devriez utiliser resize.

Une chose à propos de la réserve : si vous ajoutez ensuite des éléments avec push_back, jusqu'à ce que vous atteigniez la capacité que vous avez réservée, toutes les références, itérateurs ou pointeurs existants vers des données dans votre vecteur resteront valides. Ainsi, si je réserve 1000 et que ma taille est de 5, la fonction &vec[4] restera le même jusqu'à ce que le vecteur ait 1000 éléments. Après cela, je peux appeler push_back() et cela fonctionnera, mais le pointeur stocké de &vec[4] précédents peuvent ne plus être valables.

17voto

James Kanze Points 96599

Cela dépend de ce que vous voulez faire. reserve fait no ajouter tout éléments à la vector ; il ne change que le capacity() qui garantit que en ajoutant ne seront pas réalloués (et par ex. invalider les itérateurs). resize ajoute immédiatement des éléments. Si vous souhaitez ajouter des éléments plus tard ( insert() , push_back() ), utilisez reserve . Si vous voulez accéder aux éléments plus tard (en utilisant [] o at() ), utilisez resize . Donc vous êtes MyClass::my_method peut être soit :

void MyClass::my_method()
{
    my_member.clear();
    my_member.reserve( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member.push_back( k );
    }
}

o

void MyClass::my_method()
{
    my_member.resize( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member[k] = k;
    }
}

Le choix est une question de goût, mais le code que vous citez est le suivant clairement incorrect.

9voto

georgesl Points 4116

Répondu ici par Jan Hudec : Choix entre vector::resize() et vector::reserve()

Les deux fonctions font des choses très différentes.

La méthode resize() (et le passage de l'argument au constructeur est équivalent à cela) va insérer un nombre donné d'éléments dans le vecteur (elle a un second argument optionnel pour spécifier leur valeur). Elle affectera la méthode size(), l'itération passera sur tous ces éléments, push_back les insérera après et vous pourrez y accéder directement en utilisant l'opérateur[].

La méthode reserve() ne fait qu'allouer de la mémoire, mais la laisse non initialisée. Elle n'affecte que la capacité(), mais la taille() restera inchangée. Il n'y a pas de valeur pour les objets, car rien n'est ajouté au vecteur. Si vous insérez ensuite les éléments, aucune réallocation ne se produira, car elle a été faite à l'avance, mais c'est le seul effet.

Cela dépend donc de ce que vous voulez. Si vous voulez un tableau de 1000 éléments par défaut, utilisez resize(). Si vous voulez un tableau dans lequel vous vous attendez à insérer 1000 éléments et que vous voulez éviter quelques allocations, utilisez reserve().

EDIT : Le commentaire de Blastfurnace m'a fait relire la question et je me suis rendu compte que, dans votre cas, la bonne réponse est de ne pas préallouer manuellement. Continuez simplement à insérer les éléments à la fin selon vos besoins. Le vecteur se réallouera automatiquement selon les besoins et le fera plus efficacement que la méthode manuelle mentionnée. Le seul cas où reserve() a un sens est lorsque vous avez une estimation raisonnablement précise de la taille totale dont vous aurez besoin facilement disponible à l'avance.

EDIT2 : Question supplémentaire : Si vous avez une estimation initiale, réservez() cette estimation et si elle s'avère insuffisante, laissez le vecteur faire son travail.

4voto

Dula Points 79

Il faudrait probablement discuter du moment où les deux méthodes sont appelées avec un nombre inférieur à la taille actuelle du vecteur.

Appel à reserve() avec un nombre inférieur à la capacité n'affectera pas la taille ou la capacité.

Appel à resize() avec un nombre inférieur à la taille actuelle, le conteneur sera réduit à cette taille, détruisant ainsi les éléments en trop.

En résumé resize() libérera de la mémoire alors que reserve() ne le fera pas.

2voto

Konrad Rudolph Points 231505

Oui, vous avez raison, Luchian a juste fait une faute de frappe et est probablement trop privé de café pour se rendre compte de son erreur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X