web-dev-qa-db-fra.com

Où un std :: vector alloue-t-il sa mémoire?

Considérez l'extrait de code suivant:

#include <vector>
using namespace std;

void sub(vector<int>& vec) {
    vec.Push_back(5);
}

int main() {
    vector<int> vec(4,0);
    sub(vec);
    return 0;
}

En supposant que "vec" n'a plus d'espace pour stocker le 5 dans la fonction "sub", où alloue-t-il de la nouvelle mémoire?

Dans le cadre de pile de la sous-fonction? Dans ce cas, le 5 serait supprimé à la fin de la sous-fonction. Mais le cadre de pile de la fonction principale ne peut pas grandir, car le cadre de pile de la fonction secondaire se trouve au-dessus de la pile à ce moment.
Un vecteur std :: alloue-t-il de la mémoire pour ses éléments sur le tas? Mais comment libère-t-il cette mémoire de tas? S'il s'agit d'un vecteur local sur la pile, le cadre de pile d'une fonction incluant le vecteur est supprimé à la fin sans signaler au vecteur qu'il sera supprimé?

28
YoFrankie

Un vecteur std :: alloue-t-il de la mémoire pour ses éléments sur le tas?

Oui. Ou plus précisément, il attribue en fonction de l'allocateur que vous passez à la construction. Vous n'en avez pas spécifié un, vous obtenez donc l'allocateur par défaut. Par défaut, ce sera le tas .

Mais comment libère-t-il cette mémoire de tas?

Par son destructeur quand il sort du domaine. (Notez qu'un pointeur vers un vecteur hors de portée ne déclenchera pas le destructeur). Mais si vous aviez passé par valeur à sub vous construiriez (et plus tard, détruisez) une nouvelle copie. 5 serait alors repoussé sur cette copie, la copie serait nettoyée et le vecteur dans main serait intact.

35
Doug T.

Tous les conteneurs de la STL sont paramétrés avec des arguments de modèle, généralement le dernier argument est appelé A ou Allocator et par défaut à std::allocator<...>... représente le type de la valeur stockée dans le conteneur.

Allocator est une classe qui est utilisée pour fournir de la mémoire et construire/détruire les éléments dans cette zone de mémoire. Il peut allouer de la mémoire à partir d'un pool ou directement à partir du tas, selon la construction de l'allocateur. Par défaut, le std::allocator<T> est un simple wrapper autour de ::operator new et allouera ainsi de la mémoire sur le tas comme vous l'avez déduit.

La mémoire est allouée à la demande et est au moins désallouée lorsque le destructeur de vector est appelé. C++ 11 introduit shrink_to_fit pour libérer de la mémoire plus tôt aussi. Enfin, lorsque le vecteur dépasse sa capacité actuelle, une nouvelle allocation (plus importante) est effectuée, les objets y sont déplacés et l'ancienne allocation est libérée.

Comme toutes les variables locales, le destructeur est appelé lorsque exécuté atteint la fin de la portée dans laquelle il a été déclaré. Ainsi, avant de quitter la fonction, le destructeur de vecteur est appelé, et ce n'est qu'après que la pile se rétrécit et que le contrôle revient à l'appelant.

17
Matthieu M.

Notez également que votre vecteur (vec) est l'objet lui-même. Il réside sur la pile et lorsque cet objet sort de la portée (ce qui est la fin de main dans votre cas), il est détruit. La mémoire des éléments est allouée lors de l'initialisation de cet objet et libérée avec sa destruction, ce qui est un bel exemple de l'idiome RAII , car la gestion des ressources des éléments est liée à la durée de vie de l'objet vectoriel.

2
LihO

Parce que vous avez donné à sub l'adresse du vecteur dans le tas, elle sera allouée dans le tas. S'il n'y a plus d'espace, une exception doit être levée.

0
Stefan