Lorsque des vecteurs sont alloués, utilisent-ils de la mémoire sur le tas ou la pile?

151

Toutes les affirmations suivantes sont-elles vraies?

vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

Comment la mémoire est-elle allouée en interne Typedans un vectorou tout autre conteneur STL?

Phelodas
la source
1
Possibilité de duplication des membres
underscore_d

Réponses:

222
vector<Type> vect;

allouera les vector, c'est-à-dire les informations d'en-tête, sur la pile, mais les éléments sur le magasin libre ("tas").

vector<Type> *vect = new vector<Type>;

alloue tout sur la boutique gratuite.

vector<Type*> vect;

allouera le vectorsur la pile et un tas de pointeurs sur le magasin gratuit, mais où ces points sont déterminés par la façon dont vous les utilisez (vous pouvez pointer l'élément 0 vers le magasin libre et l'élément 1 vers la pile, par exemple).

Fred Foo
la source
3
Mais j'ai un scénario, où j'obtiens une erreur de segmentation lorsque Type devient grand sur la deuxième déclaration. Je supposais que c'était parce que Type était alloué sur la pile.
Phelodas
4
@Phelodas: sans voir votre code, c'est impossible à évaluer. Veuillez ouvrir une nouvelle question.
Fred Foo
2
À peu près vector<Type> vect;puisque les éléments sont sur le tas et que les informations d'en-tête sont sur la pile, lorsque les informations d'en-tête sont supprimées de la mémoire, comme le retour de fonction, qu'arrivera-t-il aux éléments mémoires? Sont-ils récupérés avec les informations d'en-tête ou non? Si ce n'est pas le cas, cela entraînera-t-il une fuite de mémoire?
flyrain
3
@flyrain: les vecteurs se nettoient après eux-mêmes. Renseignez-vous sur RAII .
Fred Foo
1
@flyrain: cela devrait fonctionner. Veuillez poster une nouvelle question avec plus de détails. Si vous postez le lien ici, je pourrais y jeter un œil.
Fred Foo
25
vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

Non, vectsera sur la pile, mais le tableau qu'il utilise en interne pour stocker les éléments sera sur le tas. Les éléments résideront dans ce tableau.

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Non, comme ci-dessus, sauf que la vectorclasse sera également sur le tas.

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

vectsera sur la pile, ses éléments (pointeurs vers Type) seront sur le tas, et vous ne pouvez pas dire où seront les Types vers lesquels pointent les pointeurs. Peut être sur la pile, pourrait être sur le tas, pourrait être dans les données globales, pourrait être nulle part (par exemple. NULLPointeurs).

En fait, l'implémentation pourrait en fait stocker entièrement certains vecteurs (généralement de petite taille) sur la pile. Non pas que je connaisse une telle implémentation, mais c'est possible.

jpalecek
la source
23

En supposant une implémentation qui a en fait une pile et un tas (le C ++ standard ne fait aucune obligation d'avoir de telles choses), la seule vraie déclaration est la dernière.

vector<Type> vect;
//allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

C'est vrai, sauf pour la dernière partie ( Typene sera pas sur la pile). Imaginer:

  void foo(vector<Type>& vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec.push_back(Type());
  }

  int main() {
    vector<Type> bar;
    foo(bar);
  }

Également:

 vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Vrai sauf la dernière partie, avec un exemple de compteur similaire:

  void foo(vector<Type> *vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec->push_back(Type());
  }

  int main() {
    vector<Type> *bar = new vector<Type>;
    foo(bar);
  }

Pour:

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

c'est vrai, mais notez ici que les Type*pointeurs seront sur le tas, mais les Typeinstances vers lesquelles ils pointent n'ont pas besoin d'être:

  int main() {
    vector<Type*> bar;
    Type foo;
    bar.push_back(&foo);
  }
Flexo
la source
dans quel genre de contexte n'auriez-vous pas de pile? Je comprends que vous dites que la norme ne l'exige pas, mais en pratique, quand seriez-vous sans pile?
Nerdtron
3
@Nerdtron - IIRC sur certains petits microcontrôleurs vous avez une pile d'appels qui ne peut stocker rien d'autre que le PC (compteur de programme) au point du dernier appel, prêt pour un RET. Votre compilateur peut donc choisir de placer le "stockage automatique" (pour les fonctions non récursives) dans un emplacement fixe avec peu ou pas de relation avec le flux d'exécution. Cela pourrait sensiblement aplatir l'ensemble du programme. Même pour le cas récursif, vous pouvez avoir une politique "pile par fonction" ou une pile séparée pour les variables automatiques et les adresses de retour, ce qui rend l'expression "la pile" quelque peu dénuée de sens.
Flexo
Vous pouvez utiliser l'allocation basée sur le tas pour tout et avoir une "pile de nettoyage" qui gère le stockage automatique (et peut-être deleteaussi).
Flexo
3

Seule cette affirmation est vraie:

vector <Type*> vect; //vect will be on stack and Type* will be on heap.

Type* les pointeurs sont alloués sur le tas, car la quantité de pointeurs peut changer dynamiquement.

vect dans ce cas, il est alloué sur la pile, car vous l'avez défini comme une variable de pile locale.

Alexei Khlebnikov
la source
2
Type * n'indique pas l'allocation de tas, simplement un pointeur vers un objet Type. Cela dit, le vecteur stocke le pointeur sur le tas. int a = 5; int * ptr_to_a = & a; vector <int *> vec; vec.push_back (ptr_to_a); (voir la réponse de jpalecek)
Matthew Russell
1

vector a un interne allocatorqui est chargé d'allouer / désallouer des mémoires à partir heapde vector element. Quelle que soit la manière dont vous créez un vecteur, il elementest toujours alloué sur le heap. Quant aux métadonnées du vecteur, cela dépend de la façon dont vous le créez.

Bingo
la source