En C ++, quand est-il préférable d'utiliser la pile? Quand est-il préférable d'utiliser le tas?
Réponses
Trop de publicités?En règle générale, éviter de créer d'énormes objets sur la pile.
- La création d'un objet sur la pile vous permet de vous libérer de la charge de se souvenir de nettoyage(lire la suppression) de l'objet. Mais la création de trop d'objets sur la pile d'augmenter les chances de dépassement de pile.
- Si vous utilisez segment de mémoire pour l'objet, vous obtenez le plus de mémoire le système d'exploitation peut fournir, beaucoup plus grande que la pile, mais encore une fois, vous devez assurez-vous de libérer de la mémoire lorsque vous avez terminé. Aussi, la création de trop d'objets, trop souvent dans le tas aura tendance à fragmenter la mémoire, ce qui affecte les performances de votre application.
L'utilisation de la pile lorsque la mémoire utilisée est strictement limitée à l'étendue dans laquelle vous créez. C'est utile pour éviter les fuites de mémoire parce que vous savez exactement où vous voulez utiliser la mémoire, et vous savez, quand vous n'en avez plus besoin, de sorte que la mémoire sera nettoyé pour vous.
int main()
{
if (...)
{
int i = 0;
}
// I know that i is no longer needed here, so declaring i in the above block
// limits the scope appropriately
}
Le tas, cependant, est utile lorsque votre mémoire peut être consulté à l'extérieur de la portée de sa création et que vous ne souhaitez pas copier une pile variable. Cela peut vous donner un contrôle explicite sur la façon dont la mémoire est allouée et libéré.
Object* CreateObject();
int main()
{
Object* obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done
delete obj;
// .. keep going if you wish
return 0;
}
Object* CreateObject()
{
Object* returnValue = new Object();
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back using
// a pointer
}
De toute évidence un problème commun ici, c'est que vous pouvez oublier de supprimer les de votre objet. Cela s'appelle une fuite de mémoire. Ces problèmes sont plus fréquents que votre programme devient de moins en moins trivial où la "propriété" (ou exactement qui est responsable de la suppression de choses) devient de plus en plus difficile à définir.
Des solutions communes en plus gérés langages (C#, Java) sont à mettre en œuvre la collecte des ordures de sorte que vous n'avez pas à penser à propos de la suppression de choses. Toutefois, cela signifie qu'il y a quelque chose dans le fond qui s'exécute aperiodically à vérifier sur votre tas de données. Dans un non-trivial programme, cela peut devenir plutôt inefficace comme un "garbage collection" le fil s'affiche et le souffle loin, à la recherche de données qui devraient être supprimés, tandis que le reste de votre programme est bloqué à partir de l'exécution.
En C++, le plus commun, et le mieux (à mon avis) solution pour faire face à des fuites de mémoire est d'utiliser un pointeur intelligent. Le plus commun d'entre eux est boost::shared_ptr qui est (référence compté)
Afin de recréer l'exemple ci-dessus boost::shared_ptr CreateObject();
int main()
{
boost::shared_ptr<Object> obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done, manually delete
obj.reset(NULL);
// .. keep going if you wish
// here, if you forget to delete obj, the shared_ptr's destructor will note
// that if no other shared_ptr's point to this memory
// it will automatically get deleted.
return 0;
}
boost::shared_ptr<Object> CreateObject()
{
boost::shared_ptr<Object> returnValue(new Object());
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back to
// the receiving shared_ptr, shared_ptr knows that another reference exists
// to this memory, so it shouldn't delete the memory
}
Une exception à la règle mentionnée ci-dessus, selon laquelle vous devez généralement utiliser la pile pour les variables locales qui ne sont pas nécessaires en dehors de la portée de la fonction:
Les fonctions récursives peuvent épuiser l'espace de la pile si elles allouent des variables locales volumineuses ou si elles sont invoquées de manière récursive plusieurs fois. Si vous utilisez une fonction récursive utilisant de la mémoire, il peut être judicieux d'utiliser une mémoire basée sur le tas plutôt que sur la pile.
Cette question est liée (quoique pas vraiment dupe) à quoi et où sont la pile et le tas , qui a été posée il y a quelques jours.