Au contraire, vous devriez toujours préférer les allocations de pile, dans la mesure où, en règle générale, vous ne devriez jamais avoir de nouveau / supprimer dans votre code utilisateur.
Comme vous le dites, lorsque la variable est déclarée sur la pile, son destructeur est automatiquement appelé lorsqu'elle sort du champ d'application, qui est votre principal outil pour suivre la durée de vie des ressources et éviter les fuites.
Donc, en général, chaque fois que vous avez besoin d'allouer une ressource, que ce soit de la mémoire (en appelant new), des descripteurs de fichiers, des sockets ou autre, enveloppez-la dans une classe où le constructeur acquiert la ressource et le destructeur la libère. Ensuite, vous pouvez créer un objet de ce type sur la pile et vous êtes assuré que votre ressource est libérée lorsqu'elle est hors de portée. De cette façon, vous n'avez pas à suivre vos paires nouvelles / supprimées partout pour vous assurer d'éviter les fuites de mémoire.
Le nom le plus courant de cet idiome est RAII
Examinez également les classes de pointeurs intelligents qui sont utilisées pour encapsuler les pointeurs résultants dans les rares cas où vous devez allouer quelque chose avec du nouveau en dehors d'un objet RAII dédié. Vous passez plutôt le pointeur à un pointeur intelligent, qui suit ensuite sa durée de vie, par exemple par le comptage des références, et appelle le destructeur lorsque la dernière référence sort de la portée. La bibliothèque standard a std::unique_ptr
une gestion simple basée sur l'étendue et std::shared_ptr
qui effectue le comptage des références pour implémenter la propriété partagée.
De nombreux didacticiels illustrent l'instanciation d'objets à l'aide d'un extrait de code tel que ...
Donc, ce que vous avez découvert, c'est que la plupart des tutoriels sont nulles. ;) La plupart des didacticiels vous enseignent de mauvaises pratiques C ++, y compris l'appel de new / delete pour créer des variables lorsque ce n'est pas nécessaire, et vous donnant une durée de vie difficile à suivre de vos allocations.
Bien qu'avoir des choses sur la pile puisse être un avantage en termes d'allocation et de libération automatique, cela présente certains inconvénients.
Vous ne souhaiterez peut-être pas allouer d'énormes objets sur la pile.
Envoi dynamique! Considérez ce code:
Cela imprimera "B". Voyons maintenant ce qui se passe lors de l'utilisation de Stack:
Cela affichera "A", ce qui pourrait ne pas être intuitif pour ceux qui sont familiers avec Java ou d'autres langages orientés objet. La raison en est que vous n'avez plus de pointeur vers une instance de
B
. Au lieu de cela, une instance deB
est créée et copiée dans unea
variable de typeA
.Certaines choses peuvent se produire de manière non intuitive, en particulier lorsque vous êtes nouveau dans C ++. En C, vous avez vos pointeurs et c'est tout. Vous savez comment les utiliser et ils font TOUJOURS la même chose. En C ++ ce n'est pas le cas. Imaginez simplement ce qui se passe, lorsque vous utilisez a dans cet exemple comme argument pour une méthode - les choses deviennent plus compliquées et cela fait une énorme différence s'il
a
est de typeA
ouA*
ou mêmeA&
(appel par référence). De nombreuses combinaisons sont possibles et elles se comportent toutes différemment.la source
Eh bien, la raison d'utiliser le pointeur serait exactement la même que la raison d'utiliser des pointeurs en C alloués avec malloc: si vous voulez que votre objet vive plus longtemps que votre variable!
Il est même fortement recommandé de NE PAS utiliser le nouvel opérateur si vous pouvez l'éviter. Surtout si vous utilisez des exceptions. En général, il est beaucoup plus sûr de laisser le compilateur libérer vos objets.
la source
J'ai vu cet anti-pattern de la part de personnes qui ne comprennent pas tout à fait l'opérateur & address-of. S'ils ont besoin d'appeler une fonction avec un pointeur, ils alloueront toujours sur le tas afin qu'ils obtiennent un pointeur.
la source
Traitez le tas comme un bien immobilier très important et utilisez-le de manière très judicieuse. La règle empirique de base est d'utiliser la pile chaque fois que possible et d'utiliser le tas chaque fois qu'il n'y a pas d'autre moyen. En allouant les objets sur la pile, vous pouvez obtenir de nombreux avantages tels que:
(1). Vous n'avez pas à vous soucier du déroulement de la pile en cas d'exceptions
(2). Vous n'avez pas à vous soucier de la fragmentation de la mémoire causée par l'allocation de plus d'espace que nécessaire par votre gestionnaire de tas.
la source
La seule raison pour laquelle je m'inquiéterais est que Dog est maintenant alloué sur la pile, plutôt que sur le tas. Donc, si Dog a une taille de mégaoctets, vous pouvez avoir un problème,
Si vous devez emprunter la nouvelle route / supprimer, méfiez-vous des exceptions. Et à cause de cela, vous devez utiliser auto_ptr ou l'un des types de pointeurs intelligents boost pour gérer la durée de vie de l'objet.
la source
Il n'y a aucune raison de créer un nouveau (sur le tas) lorsque vous pouvez allouer sur la pile (sauf si pour une raison quelconque vous avez une petite pile et que vous souhaitez utiliser le tas.
Vous pouvez envisager d'utiliser un shared_ptr (ou l'une de ses variantes) de la bibliothèque standard si vous souhaitez allouer sur le tas. Cela gérera la suppression pour vous une fois que toutes les références à shared_ptr auront disparu.
la source
Il y a une raison supplémentaire, que personne d'autre n'a mentionnée, pour laquelle vous pourriez choisir de créer votre objet dynamiquement. Les objets dynamiques basés sur des tas vous permettent d'utiliser le polymorphisme .
la source
J'ai eu le même problème dans Visual Studio. Vous devez utiliser:
yourClass-> classMethod ();
plutôt que:
yourClass.classMethod ();
la source