std::vector::resize() vs std::vector::réserve()

il y a un fil dans la section des commentaires dans ce post à propos de l'utilisation de 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 éléments dans le vector , la bonne chose à faire est d'appeler std::vector::resize() , pas std::vector::reserve() .

en fait, le code de test suivant "crashes" dans debug builds 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 est-ce que VS2010 SP1 est juste, ou est-ce faux?

58
demandé sur Community 2012-10-23 15:19:35

6 réponses

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

std::vector::reserve attribuera la mémoire mais ne redimensionnera pas votre vecteur, qui aura une taille logique identique à celle d'avant.

std::vector::resize modifiera en fait la taille de votre vecteur et remplira n'importe quel espace avec des objets dans leur état par défaut. S'ils sont entiers, ils seront tous à zéro.

après réserve, dans votre cas, vous aurez besoin de beaucoup de push_backs pour écrire à l'élément 5. Si vous ne souhaitez pas que dans votre cas, vous devez utiliser redimensionner.

88
répondu CashCow 2012-10-23 11:24:03

, a Répondu ici par Jan Hudec : Choix entre le vecteur::resize() et de vecteur::reserve()

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

la méthode resize () (et passer l'argument au constructeur est équivalent à cela) insérera un nombre donné d'éléments au vecteur (il a un second argument optionnel pour spécifier leur valeur). Il affectera la taille (), l'itération sera plus de tous ces éléments, push_back va insérer après eux et vous pouvez directement y accéder en utilisant l'opérateur[].

la méthode reserve() n'affecte que la mémoire, mais la laisse non initialisée. Il n'affecte que la capacité(), mais la taille() sera inchangée. Il n'y a aucune valeur pour les objets, parce que rien n'est ajouté au vecteur. Si vous insérez alors les éléments, aucune réallocation ne se produira, parce que cela a été fait à l'avance, mais c'est le seul effet.

donc ça dépend de ce que vous voulez. Si vous voulez un tableau de 1000 éléments par défaut, utilisez resize(). Si vous voulez un tableau auquel vous prévoyez d'insérer 1000 articles et que vous voulez éviter quelques allocations, utilisez reserve().

EDIT: le commentaire de Blastfurnace m'a fait relire la question et réaliser, que dans votre cas la bonne réponse est ne pas préallouer manuellement. Il suffit de continuer à insérer les éléments à la fin comme vous avez besoin. Le vecteur sera automatiquement réaffecter comme nécessaire et le fera de manière plus efficace que la méthode manuelle mentionnée. Le seul cas où reserve() a du sens est lorsque vous avez une estimation assez précise de la taille totale dont vous aurez besoin facilement disponible à l'avance.

EDIT2: Ad question edit: Si vous avez une estimation initiale, de la réserve() l'estimation et, si elle s'avère pas suffisant, il suffit de laisser le vecteur de le faire.

20
répondu lucasg 2017-05-23 12:03:05

Cela dépend de ce que vous voulez faire. reserve ne pas "1519150920 d'ajouter tout éléments du vector ; il ne modifie que le capacity() , qui garanties que ajout de éléments ne seront pas réaffectés (et par exemple invalider les itérateurs). resize , ajoute des éléments immédiatement. Si vous voulez ajouter des éléments plus tard ( insert() , push_back() ), utilisez reserve . Si vous vous voulez accéder à des éléments plus tard (en utilisant [] ou at() ), utilisez resize . Si 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 );
    }
}

ou

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

Qui vous avez choisi est une question de goût, mais le code que vous citez est clairement erronée.

11
répondu James Kanze 2014-06-03 16:00:05

Oui vous avez raison, Luchian vient de faire une faute de frappe et est probablement trop privé de café pour réaliser son erreur.

2
répondu Konrad Rudolph 2012-10-23 11:22:35

il devrait probablement y avoir une discussion sur le moment où les deux méthodes sont appelées avec un nombre qui est inférieur à la taille actuelle du vecteur.

Appel reserve() avec un nombre plus petit que la capacité n'affectera pas la taille ou la capacité.

Appel resize() avec un nombre plus petit que la taille actuelle du conteneur sera réduit à la taille efficace de détruire les éléments excédentaires.

pour résumer resize() va libérer la mémoire tandis que reserve() ne le fera pas.

2
répondu Dula 2015-07-07 21:32:37

redimensionner change en fait la quantité d'éléments dans le vecteur, de nouveaux éléments sont construits par défaut si le redimensionnement fait croître le vecteur.

vector<int> v;
v.resize(10);
auto size = v.size();

dans ce cas, la taille est de 10.

reserve d'autre part demande seulement que le tampon interne soit augmenté à la taille spécifiée mais ne change pas la "taille" du tableau, seule sa taille de tampon est changée.

vector<int> v;
v.reserve(10);
auto size = v.size();

dans ce cas la taille est toujours 0.

donc pour répondre à votre question, oui vous avez raison, même si vous réservez assez d'espace, vous accédez toujours à la mémoire non initialisée avec l'opérateur index. Avec un int ce n'est pas si mauvais, mais dans le cas d'un vecteur de classes serait l'accès à des objets qui n'ont pas été construits.

la vérification des limites des compilateurs mis en mode de débogage peut évidemment être confondue par ce comportement qui peut être la raison pour laquelle vous éprouvez le crash.

1
répondu odinthenerd 2012-10-23 11:33:51