48 votes

C++ Comment allouer dynamiquement de la mémoire sur la pile ?

Existe-t-il un moyen d'allouer de la mémoire sur pile au lieu de tas ? Je n'arrive pas à trouver un bon livre sur ce sujet, quelqu'un ici a une idée ?

0 votes

Si vous souhaitez contrôler l'endroit où un std::string ou un std::vector alloue sa mémoire, consultez cette question : stackoverflow.com/questions/354442/

1 votes

@Neil : pour allouer/libérer rapidement un espace de travail temporaire ?

0 votes

@Neil Butterworth Exemple : vous devez allouer une quantité variable d'espace pour un tampon temporaire pendant que vous triez les sommets par profondeur. Les sommets proviennent de données d'exécution, vous ne savez donc pas à l'avance combien vous en aurez. De plus, vous disposez d'un budget de 2 microsecondes pour l'ensemble de la fonction, et sur votre plate-forme, malloc() coûte 1 microseconde.

58voto

Crashworks Points 22920

Utilisez alloca() (parfois appelé _alloca() o _malloca() ), mais soyez très prudent à ce sujet - il libère sa mémoire lorsque vous quittez une fonction, et non lorsque vous sortez du champ d'application, ce qui fait que vous allez rapidement exploser si vous l'utilisez à l'intérieur d'une boucle.

Par exemple, si vous avez une fonction comme

int foo( int nDataSize, int iterations ) 
{
   for ( int i = 0; i < iterations ; ++i )
   {
      char *bytes = alloca( nDataSize );
      // the memory above IS NOT FREED when we pass the brace below!
   } 
   return 0;
}  // alloca() memory only gets freed here

Ensuite, la fonction alloca() allouera un fichier supplémentaire nDataSize octets à chaque fois dans la boucle . Aucun des octets alloca() n'est libéré avant le retour de la fonction. Ainsi, si vous avez un nDataSize de 1024 et un iterations de 8, vous allouerez 8 kilo-octets avant de revenir. Si vous avez un nDataSize = 65536 et iterations = 32768, vous allouerez un total de 65536×32768=2 147 483 648 octets, ce qui fera presque certainement exploser votre pile et provoquera un crash.

anecdote : Vous pouvez facilement avoir des problèmes si vous écrivez au-delà de la fin du tampon, surtout si vous passez le tampon dans une autre fonction et que cette sous-fonction a une idée erronée de la longueur du tampon. J'ai une fois corrigé un bug plutôt amusant où nous utilisions alloca() pour créer un stockage temporaire pour le rendu d'un glyphe de police TrueType avant de l'envoyer dans la mémoire du GPU. Notre bibliothèque de polices n'a pas pris en compte le diacritique du caractère suédois Å lors du calcul de la taille des glyphes, et nous a donc demandé d'allouer la mémoire du GPU à la police TrueType. n octets pour stocker le glyphe avant le rendu, puis effectivement rendu n +128 octets. Les 128 octets supplémentaires ont été écrits dans la pile d'appel, écrasant l'adresse de retour et provoquant un crash non déterministe très douloureux !

9voto

Steve Townsend Points 36948

Comme il s'agit de C++ balisé, il suffit généralement de déclarer les objets dont on a besoin dans la bonne portée. Ils sont alloués sur la pile, et leur libération est garantie à la sortie de la portée. Ceci est RAII et un avantage essentiel de C++ par rapport à C. Non malloc ou new et surtout pas de alloca s, nécessaires.

2 votes

Le problème ici est que de nombreux objets C++ s'allouent de la mémoire pour eux-mêmes.

0 votes

@Zan Lynx - c'est sûr. Mais dans quel scénario alloueriez-vous un tel graphe d'objets sur la pile ?

8 votes

Vous pouvez appeler une fonction qui remplit un vecteur. Vous pouvez avoir besoin d'une chaîne de caractères. Vous pouvez avoir besoin que ces choses soient très rapides et sans risque pour les threads. Si vous n'avez pas besoin que ces choses vivent au-delà de la fonction, alors le stockage en pile est exactement le bon endroit.

3voto

Dan Points 1748

Voir _malloca .

0 votes

Il faut mentionner que le C++ n'est pas standard.

3voto

DuckMaestro Points 4941

Vous pouvez déclarer un char[1024] ou le nombre d'octets que vous souhaitez (jusqu'à un certain point), puis prenez l'adresse du local pour un pointeur vers ce bloc de mémoire sur la pile. Ce n'est pas exactement dynamique, mais vous pouvez ensuite envelopper cette mémoire avec votre propre gestionnaire de mémoire si vous le souhaitez.

1 votes

Ce devrait être la deuxième meilleure réponse à cette question spécifique, si ce n'est la réponse acceptée. Elle est propre et simple, contrairement à la réponse _alloca.

6 votes

@MarkusL.Clean simple et mauvais parce que la question porte spécifiquement sur l'allocation dynamique (et non statique) de la pile.

2voto

Sammy Points 21

Article traitant de l'allocation dynamique de la mémoire

Nous pouvons allouer dynamiquement de l'espace de longueur variable sur la mémoire de la pile en utilisant la fonction _alloca. Cette fonction alloue de la mémoire à partir de la pile du programme. Elle prend simplement le nombre d'octets à allouer et retourne void* à l'utilisateur. l'espace alloué tout comme l'appel malloc. Cette mémoire allouée sera libérée automatiquement à la sortie de la fonction.

Il n'est donc pas nécessaire de le libérer explicitement. Il faut garder à l'esprit la taille taille de l'allocation, car une exception de débordement de pile peut se produire. Pile peut être utilisé pour de tels appels. En cas de exception de débordement de pile, on peut utiliser _resetstkoflw() pour le restaurer retour.

Ainsi, notre nouveau code avec _alloca serait :

int NewFunctionA()
{
   char* pszLineBuffer = (char*) _alloca(1024*sizeof(char));
    …..
  // Program logic
     ….
  //no need to free szLineBuffer
  return 1;
}

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