Il existe deux techniques d'allocation de mémoire largement utilisées: l'allocation automatique et l'allocation dynamique. Généralement, il existe une région de mémoire correspondante pour chacun: la pile et le tas.
Empiler
La pile alloue toujours la mémoire de manière séquentielle. Il peut le faire car il vous oblige à libérer la mémoire dans l'ordre inverse (First-In, Last-Out: FILO). Il s'agit de la technique d'allocation de mémoire pour les variables locales dans de nombreux langages de programmation. Il est très, très rapide car il nécessite une comptabilité minimale et la prochaine adresse à allouer est implicite.
En C ++, cela s'appelle le stockage automatique car le stockage est revendiqué automatiquement à la fin de la portée. Dès que l'exécution du bloc de code actuel (délimité par {}
) est terminée, la mémoire de toutes les variables de ce bloc est automatiquement collectée. C'est également le moment où les destructeurs sont appelés pour nettoyer les ressources.
Tas
Le tas permet un mode d'allocation de mémoire plus flexible. La comptabilité est plus complexe et l'allocation est plus lente. Puisqu'il n'y a pas de point de libération implicite, vous devez libérer la mémoire manuellement, en utilisant delete
ou delete[]
( free
en C). Cependant, l'absence d'un point de sortie implicite est la clé de la flexibilité du tas.
Raisons d'utiliser l'allocation dynamique
Même si l'utilisation du segment de mémoire est plus lente et peut entraîner des fuites de mémoire ou une fragmentation de la mémoire, il existe des cas d'utilisation parfaits pour l'allocation dynamique, car elle est moins limitée.
Deux raisons principales d'utiliser l'allocation dynamique:
Vous ne savez pas de combien de mémoire vous avez besoin au moment de la compilation. Par exemple, lorsque vous lisez un fichier texte dans une chaîne, vous ne savez généralement pas quelle est la taille du fichier, vous ne pouvez donc pas décider de la quantité de mémoire à allouer avant d'exécuter le programme.
Vous souhaitez allouer de la mémoire qui persistera après avoir quitté le bloc actuel. Par exemple, vous souhaiterez peut-être écrire une fonction string readfile(string path)
qui renvoie le contenu d'un fichier. Dans ce cas, même si la pile pouvait contenir tout le contenu du fichier, vous ne pouviez pas revenir d'une fonction et conserver le bloc de mémoire alloué.
Pourquoi l'allocation dynamique est souvent inutile
En C ++, il y a une construction soignée appelée destructeur . Ce mécanisme vous permet de gérer les ressources en alignant la durée de vie de la ressource avec la durée de vie d'une variable. Cette technique est appelée RAII et est le point distinctif du C ++. Il "enveloppe" les ressources en objets. std::string
est un parfait exemple. Cet extrait:
int main ( int argc, char* argv[] )
{
std::string program(argv[0]);
}
alloue en fait une quantité variable de mémoire. L' std::string
objet alloue de la mémoire à l'aide du tas et la libère dans son destructeur. Dans ce cas, vous n'avez pas eu besoin de gérer manuellement les ressources et bénéficiez quand même des avantages de l'allocation dynamique de mémoire.
En particulier, cela implique que dans cet extrait:
int main ( int argc, char* argv[] )
{
std::string * program = new std::string(argv[0]); // Bad!
delete program;
}
il y a une allocation de mémoire dynamique inutile. Le programme nécessite plus de frappe (!) Et présente le risque d'oublier de désallouer la mémoire. Il le fait sans aucun avantage apparent.
Pourquoi utiliser le stockage automatique aussi souvent que possible
Fondamentalement, le dernier paragraphe le résume. Utiliser le stockage automatique aussi souvent que possible rend vos programmes:
- plus rapide à taper;
- plus rapide lors de l'exécution;
- moins sujettes aux fuites de mémoire / ressources.
Points bonus
Dans la question référencée, il existe des préoccupations supplémentaires. En particulier, la classe suivante:
class Line {
public:
Line();
~Line();
std::string* mString;
};
Line::Line() {
mString = new std::string("foo_bar");
}
Line::~Line() {
delete mString;
}
Est en fait beaucoup plus risqué à utiliser que le suivant:
class Line {
public:
Line();
std::string mString;
};
Line::Line() {
mString = "foo_bar";
// note: there is a cleaner way to write this.
}
La raison en est que std::string
définit correctement un constructeur de copie. Considérez le programme suivant:
int main ()
{
Line l1;
Line l2 = l1;
}
En utilisant la version d'origine, ce programme se bloquera probablement, car il utilise delete
deux fois la même chaîne. En utilisant la version modifiée, chaque Line
instance possédera sa propre instance de chaîne , chacune avec sa propre mémoire et les deux seront publiées à la fin du programme.
Autres notes
L'utilisation intensive de RAII est considérée comme une meilleure pratique en C ++ pour toutes les raisons ci-dessus. Cependant, il existe un avantage supplémentaire qui n'est pas immédiatement évident. Fondamentalement, c'est mieux que la somme de ses parties. L'ensemble du mécanisme compose . Il évolue.
Si vous utilisez la Line
classe comme bloc de construction:
class Table
{
Line borders[4];
};
alors
int main ()
{
Table table;
}
alloue quatre std::string
instances, quatre Line
instances, une Table
instance et tout le contenu de la chaîne et tout est libéré automatiquement .
Monster
crache unTreasure
auWorld
moment de sa mort. Dans saDie()
méthode, il ajoute le trésor au monde. Il doit l'utiliserworld->Add(new Treasure(/*...*/))
dans d'autres pour conserver le trésor après sa mort. Les alternatives sontshared_ptr
(peuvent être exagérées),auto_ptr
(mauvaise sémantique pour le transfert de propriété), passer par la valeur (gaspillage) etmove
+unique_ptr
(pas encore largement mises en œuvre).Parce que la pile est plus rapide et étanche
En C ++, il suffit d'une seule instruction pour allouer de l'espace - sur la pile - pour chaque objet de portée locale dans une fonction donnée, et il est impossible de divulguer une partie de cette mémoire. Ce commentaire avait l'intention (ou aurait dû avoir l'intention) de dire quelque chose comme "utilisez la pile et non le tas".
la source
int x; return &x;
La raison en est compliquée.
Tout d'abord, C ++ n'est pas récupéré. Par conséquent, pour chaque nouveau, il doit y avoir une suppression correspondante. Si vous ne parvenez pas à insérer cette suppression, vous avez une fuite de mémoire. Maintenant, pour un cas simple comme celui-ci:
C’est simple. Mais que se passe-t-il si "Do stuff" lève une exception? Oups: fuite de mémoire. Que se passe-t-il si "Do stuff" émet
return
tôt? Oups: fuite de mémoire.Et c'est pour le cas le plus simple . S'il vous arrive de renvoyer cette chaîne à quelqu'un, il doit maintenant la supprimer. Et s'ils la transmettent comme argument, la personne qui la reçoit doit-elle la supprimer? Quand devraient-ils le supprimer?
Ou, vous pouvez simplement faire ceci:
Non
delete
. L'objet a été créé sur la "pile", et il sera détruit une fois hors de portée. Vous pouvez même renvoyer l'objet, transférant ainsi son contenu à la fonction appelante. Vous pouvez passer l'objet à des fonctions (généralement comme référence ou const-référence:.void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis)
Et ainsi de suite.Le tout sans
new
etdelete
. Il n'est pas question de savoir qui possède la mémoire ou qui est responsable de sa suppression. Si tu fais:Il est entendu que
otherString
possède une copie des données desomeString
. Ce n'est pas un pointeur; c'est un objet séparé. Il se peut qu'ils aient le même contenu, mais vous pouvez en modifier un sans affecter l'autre:Vous voyez l'idée?
la source
main()
, existe pour la durée du programme, ne peut pas être facilement créé sur la pile en raison de la situation, et des pointeurs vers celui-ci sont passés à toutes les fonctions qui nécessitent un accès à celui-ci , cela peut-il provoquer une fuite en cas de plantage du programme, ou serait-ce sûr? Je supposerais ce dernier, car le système d'exploitation désallouant toute la mémoire du programme devrait également le désallouer logiquement, mais je ne veux rien supposer en ce qui concernenew
.Les objets créés par
new
doivent finir pardelete
ne pas fuir. Le destructeur ne sera pas appelé, la mémoire ne sera pas libérée, le tout. Comme C ++ n'a pas de récupération de place, c'est un problème.Les objets créés par la valeur (c'est-à-dire sur la pile) meurent automatiquement lorsqu'ils sortent de la portée. L'appel du destructeur est inséré par le compilateur et la mémoire est automatiquement libérée au retour de la fonction.
Les pointeurs intelligents comme
unique_ptr
,shared_ptr
résolvent le problème de référence pendant, mais ils nécessitent une discipline de codage et ont d'autres problèmes potentiels (copie, boucles de référence, etc.).En outre, dans les scénarios fortement multithreads, il
new
existe un point de discorde entre les threads; il peut y avoir un impact sur les performances en cas de surutilisationnew
. La création d'objets de pile est par définition thread locale, car chaque thread a sa propre pile.L'inconvénient des objets de valeur est qu'ils meurent une fois la fonction hôte revenue - vous ne pouvez pas transmettre une référence à ceux qui reviennent à l'appelant, uniquement en copiant, en retournant ou en se déplaçant par valeur.
la source
new
doivent être finalementdelete
peur de ne pas fuir." - pire encore,new[]
doit correspondredelete[]
, et vous obtenez un comportement indéfini si vous avez de ladelete
new[]
mémoire ou de ladelete[]
new
mémoire - très peu de compilateurs avertissent à ce sujet (certains outils comme Cppcheck le font quand ils le peuvent).la source
malloc()
ou à ses amis pour allouer la mémoire requise. Cependant, la pile ne peut libérer aucun élément de la pile, la seule façon dont la mémoire de la pile est libérée est le déroulement du haut de la pile.Je vois que quelques raisons importantes pour faire le moins de nouveautés possibles sont manquées:
L'opérateur
new
a un temps d'exécution non déterministeL'appel
new
peut ou non obliger le système d'exploitation à allouer une nouvelle page physique à votre processus, cela peut être assez lent si vous le faites souvent. Ou il peut déjà avoir un emplacement de mémoire approprié prêt, nous ne savons pas. Si votre programme doit avoir un temps d'exécution cohérent et prévisible (comme dans un système en temps réel ou une simulation de jeu / physique), vous devez éviternew
dans vos boucles critiques de temps.L'opérateur
new
est une synchronisation de thread impliciteOui, vous m'avez entendu, votre système d'exploitation doit s'assurer que vos tableaux de pages sont cohérents et, en tant que tel, l'appel
new
entraînera l'acquisition par votre thread d'un verrou mutex implicite. Si vous appelez régulièrement ànew
partir de nombreux threads, vous sérialisez réellement vos threads (je l'ai fait avec 32 processeurs, chacun frappantnew
pour obtenir quelques centaines d'octets chacun, aïe! C'était un pita royal à déboguer)Le reste tel que lent, fragmentation, sujet aux erreurs, etc. a déjà été mentionné par d'autres réponses.
la source
void * someAddress = ...; delete (T*)someAddress
mlock()
ou quelque chose de similaire. Cela est dû au fait que le système peut manquer de mémoire et qu'il n'y a pas de pages de mémoire physique disponibles pour la pile, de sorte que le système d'exploitation peut avoir besoin d'échanger ou d'écrire des caches (effacer la mémoire sale) sur le disque avant que l'exécution puisse continuer.Pré-C ++ 17:
Parce qu'il est sujet à des fuites subtiles même si vous enveloppez le résultat dans un pointeur intelligent .
Considérons un utilisateur "prudent" qui se souvient d'encapsuler des objets dans des pointeurs intelligents:
Ce code est dangereux parce qu'il n'y a aucune garantie que ce soit
shared_ptr
est construit avant soitT1
ouT2
. Par conséquent, si l'unnew T1()
ounew T2()
échoue après que l'autre réussit, alors le premier objet sera divulgué car ilshared_ptr
n'existe pas pour le détruire et le désallouer.Solution: utiliser
make_shared
.Post-C ++ 17:
Ce n'est plus un problème: C ++ 17 impose une contrainte sur l'ordre de ces opérations, en s'assurant dans ce cas que chaque appel ànew()
doit être immédiatement suivi de la construction du pointeur intelligent correspondant, sans aucune autre opération entre les deux. Cela implique qu'au moment où le secondnew()
est appelé, il est garanti que le premier objet a déjà été encapsulé dans son pointeur intelligent, empêchant ainsi toute fuite en cas de levée d'une exception.Une autre réponse a fourni une explication plus détaillée du nouvel ordre d'évaluation introduit par C ++ 17 .Merci à @Remy Lebeau pour avoir signalé que c'est toujours un problème sous C ++ 17 (bien que moins): le
shared_ptr
constructeur peut ne pas allouer son bloc de contrôle et lancer, auquel cas le pointeur qui lui est passé n'est pas supprimé.Solution: utiliser
make_shared
.la source
new
succès, puis lashared_ptr
construction suivante échoue.std::make_shared()
résoudrait cela aussishared_ptr
constructeur en question alloue de la mémoire à un bloc de contrôle qui stocke le pointeur et le deleter partagés, donc oui, il peut théoriquement générer une erreur de mémoire. Seuls les constructeurs de copie, de déplacement et d'alias ne sont pas lancés.make_shared
alloue l'objet partagé à l'intérieur du bloc de contrôle lui-même, il n'y a donc qu'une seule allocation au lieu de 2.Dans une large mesure, c'est quelqu'un qui élève ses propres faiblesses à une règle générale. Il n'y a rien de mal en soi à créer des objets à l'aide de l'
new
opérateur. Il y a un argument pour dire que vous devez le faire avec une certaine discipline: si vous créez un objet, vous devez vous assurer qu'il va être détruit.La façon la plus simple de le faire est de créer l'objet en stockage automatique, donc C ++ sait le détruire lorsqu'il sort du domaine:
Maintenant, observez que lorsque vous tombez de ce bloc après l'accolade d'extrémité, il
foo
est hors de portée. C ++ appellera automatiquement son dtor pour vous. Contrairement à Java, vous n'avez pas besoin d'attendre que le GC le trouve.Aviez-vous écrit
vous souhaitez faire correspondre explicitement avec
ou encore mieux, allouez votre
File *
comme un "pointeur intelligent". Si vous n'y faites pas attention, cela peut entraîner des fuites.La réponse elle-même fait l'hypothèse erronée que si vous n'utilisez pas,
new
vous n'allouez pas sur le tas; en fait, en C ++, vous ne le savez pas. Tout au plus, vous savez qu'une petite quantité de mémoire, disons un pointeur, est certainement allouée sur la pile. Cependant, considérez si l'implémentation de File est quelque chose commepuis
FileImpl
seront encore attribués sur la pile.Et oui, vous feriez mieux d'être sûr d'avoir
dans la classe aussi; sans cela, vous fuierez la mémoire du tas même si vous ne l'avez apparemment pas alloué du tout.
la source
new
soi , mais si vous regardez le code d'origine auquel le commentaire faisait référence,new
est abusé. Le code est écrit comme s'il s'agissait de Java ou C #, où ilnew
est utilisé pour pratiquement toutes les variables, lorsque les choses ont beaucoup plus de sens d'être sur la pile.new
. Il indique que si vous avez le choix entre l'allocation dynamique et le stockage automatique, utilisez le stockage automatique.new
, mais si vous utilisezdelete
, vous le faites mal!new()
ne doit pas être utilisé le moins possible. Il doit être utilisé aussi soigneusement que possible. Et il devrait être utilisé aussi souvent que nécessaire, comme le dictait le pragmatisme.L'allocation d'objets sur la pile, en s'appuyant sur leur destruction implicite, est un modèle simple. Si la portée requise d'un objet correspond à ce modèle, il n'est pas nécessaire de l'utiliser
new()
, avec lesdelete()
pointeurs NULL associés et vérifiés. Dans le cas où vous avez beaucoup d'allocation d'objets de courte durée sur la pile, cela devrait réduire les problèmes de fragmentation du tas.Cependant, si la durée de vie de votre objet doit dépasser la portée actuelle,
new()
c'est la bonne réponse. Assurez-vous simplement de faire attention à quand et comment vous appelezdelete()
et aux possibilités des pointeurs NULL, en utilisant des objets supprimés et tous les autres pièges fournis avec l'utilisation de pointeurs.la source
const
ref ou pointeur ...?make_shared/_unique
est utilisable) l'appelé n'a jamais besoin denew
oudelete
. Cette réponse manque les vrais points: (A) C ++ fournit des choses comme RVO, déplacer la sémantique et les paramètres de sortie - ce qui signifie souvent que la gestion de la création d'objet et de l'extension de la durée de vie en retournant la mémoire allouée dynamiquement devient inutile et négligente. (B) Même dans les situations où l'allocation dynamique est requise, le stdlib fournit des wrappers RAII qui soulagent l'utilisateur des moindres détails intérieurs.Lorsque vous utilisez new, les objets sont alloués au tas. Il est généralement utilisé lorsque vous prévoyez une expansion. Lorsque vous déclarez un objet tel que,
il est placé sur la pile.
Vous devrez toujours appeler destroy sur l'objet que vous avez placé sur le tas avec new. Cela ouvre la possibilité de fuites de mémoire. Les objets placés sur la pile ne sont pas sujets à des fuites de mémoire!
la source
std::string
oustd::map
, oui, un aperçu perspicace. Ma réaction initiale a été "mais aussi très souvent de découpler la durée de vie d'un objet de la portée du code de création", mais vraiment retourner par valeur ou accepter les valeurs de la portée de l'appelant par nonconst
référence ou pointeur est mieux pour cela, sauf quand il y a "expansion" impliquée aussi. Il y a cependant d'autres utilisations sonores comme les méthodes d'usine ....Une raison notable pour éviter de trop utiliser le tas est pour les performances - impliquant spécifiquement les performances du mécanisme de gestion de la mémoire par défaut utilisé par C ++. Alors que l'allocation peut être assez rapide dans le cas trivial, faire beaucoup
new
etdelete
sur des objets de taille non uniforme sans ordre strict entraîne non seulement une fragmentation de la mémoire, mais complique également l'algorithme d'allocation et peut absolument détruire les performances dans certains cas.C'est le problème que les pools de mémoire ont été créés pour résoudre, ce qui permet d'atténuer les inconvénients inhérents aux implémentations de tas traditionnelles, tout en vous permettant d'utiliser le tas si nécessaire.
Mieux encore, cependant, pour éviter complètement le problème. Si vous pouvez le mettre sur la pile, faites-le.
la source
Je pense que l'affiche voulait dire
You do not have to allocate everything on the
heap
plutôt que lestack
.Fondamentalement, les objets sont alloués sur la pile (si la taille de l'objet le permet, bien sûr) en raison du coût bon marché de l'allocation de pile, plutôt que de l'allocation basée sur le tas qui implique un certain travail par l'allocateur, et ajoute de la verbosité car alors vous devez gérer les données allouées sur le tas.
la source
J'ai tendance à être en désaccord avec l'idée d'utiliser de nouveaux «trop». Bien que l'utilisation originale de new avec les classes système par l'affiche originale soit un peu ridicule. (
int *i; i = new int[9999];
? vraiment?int i[9999];
est beaucoup plus clair.) Je pense que c'est ce qui a attiré la chèvre du commentateur.Lorsque vous travaillez avec des objets système, il est très rare que vous ayez besoin de plusieurs références au même objet. Tant que la valeur est la même, c'est tout ce qui compte. Et les objets système n'occupent généralement pas beaucoup d'espace en mémoire. (un octet par caractère, dans une chaîne). Et s'ils le font, les bibliothèques doivent être conçues pour prendre en compte cette gestion de la mémoire (si elles sont bien écrites). Dans ces cas, (toutes sauf une ou deux des nouvelles de son code), new est pratiquement inutile et ne sert qu'à introduire des confusions et un potentiel de bugs.
Cependant, lorsque vous travaillez avec vos propres classes / objets (par exemple la classe Line de l'affiche originale), vous devez commencer à penser vous-même aux problèmes tels que l'empreinte mémoire, la persistance des données, etc. À ce stade, autoriser plusieurs références à la même valeur est inestimable - il permet des constructions comme des listes liées, des dictionnaires et des graphiques, où plusieurs variables doivent non seulement avoir la même valeur, mais référencer exactement le même objet en mémoire. Cependant, la classe Line n'a aucune de ces exigences. Ainsi, le code de l'affiche originale n'a absolument aucun besoin
new
.la source
When you're working with your own classes/objects
... vous n'avez souvent aucune raison de le faire! Une infime proportion de questions-réponses porte sur les détails de la conception des conteneurs par des codeurs qualifiés. À l' opposé, une proportion déprimant sont de la confusion des débutants qui ne connaissent pas le stdlib existe - ou sont activement donné des missions terribles dans la « programmation » des « cours », où un tuteur exige qu'ils réinventent la roue inutilement - avant même de appris ce qu'est une roue et pourquoi elle fonctionne. En favorisant une allocation plus abstraite, C ++ peut nous sauver du «segfault sans fin avec liste liée» de C; s'il vous plaît, nous allons laisser cela .int *i; i = new int[9999];
? vraiment?int i[9999];
est beaucoup plus clair.)" Oui, c'est plus clair, mais pour jouer l'avocat du diable, le type n'est pas nécessairement un mauvais argument. Avec 9999 éléments, je peux imaginer un système embarqué serré n'ayant pas assez de pile pour 9999 éléments: 9999x4 octets est ~ 40 Ko, x8 ~ 80 Ko. De tels systèmes peuvent donc avoir besoin d'utiliser l'allocation dynamique, en supposant qu'ils l'implémentent en utilisant une mémoire alternative. Pourtant, cela ne pouvait peut-être que justifier une allocation dynamique, nonnew
; unvector
serait la vraie solution dans ce casstd::make_unique<int[]>()
bien sûr).Deux raisons:
delete
plus tard, sinon cela entraînera une fuite de mémoire.la source
new
est le nouveaugoto
.Rappelez-vous pourquoi il
goto
est si vilipendé: bien qu'il s'agisse d'un outil puissant et de bas niveau pour le contrôle de flux, les gens l'utilisaient souvent de manière inutilement compliquée, ce qui rendait le code difficile à suivre. De plus, les modèles les plus utiles et les plus faciles à lire étaient codés dans des instructions de programmation structurées (par exemplefor
ouwhile
); l'effet ultime est que le code oùgoto
est le moyen approprié est plutôt rare, si vous êtes tenté d'écriregoto
, vous faites probablement mal les choses (sauf si vous savez vraiment ce que vous faites).new
est similaire - il est souvent utilisé pour rendre les choses inutilement compliquées et plus difficiles à lire, et les modèles d'utilisation les plus utiles peuvent être codés ont été codés dans différentes classes. De plus, si vous avez besoin d'utiliser de nouveaux modèles d'utilisation pour lesquels il n'y a pas déjà de classes standard, vous pouvez écrire vos propres classes qui les encodent!Je dirais même que
new
c'est pire quegoto
, en raison de la nécessité de jumelernew
et dedelete
déclarations.Par exemple
goto
, si vous pensez que vous devez utilisernew
, vous faites probablement mal les choses - surtout si vous le faites en dehors de la mise en œuvre d'une classe dont le but dans la vie est d'encapsuler les allocations dynamiques que vous devez faire.la source
La raison principale est que les objets sur le tas sont toujours difficiles à utiliser et à gérer que les valeurs simples. Écrire du code facile à lire et à maintenir est toujours la première priorité de tout programmeur sérieux.
Un autre scénario est que la bibliothèque que nous utilisons fournit une sémantique de valeur et rend l'allocation dynamique inutile.
Std::string
est un bon exemple.Pour le code orienté objet, cependant, l'utilisation d'un pointeur - ce qui signifie
new
que vous devez le créer au préalable - est un must. Afin de simplifier la complexité de la gestion des ressources, nous avons des dizaines d'outils pour la rendre aussi simple que possible, comme des pointeurs intelligents. Le paradigme basé sur les objets ou le paradigme générique suppose une sémantique de valeur et nécessite moins ou pasnew
, tout comme les affiches énoncées ailleurs.Les modèles de conception traditionnels, en particulier ceux mentionnés dans le livre du GoF , en utilisent
new
beaucoup, car ils sont du code OO typique.la source
For object oriented code, using a pointer [...] is a must
: un non - sens . Si vous dévaluez 'OO' en vous référant uniquement à un petit sous-ensemble, le polymorphisme - aussi un non-sens: les références fonctionnent aussi.[pointer] means use new to create it beforehand
: particulièrement absurde : des références ou des pointeurs peuvent être utilisés pour les objets alloués automatiquement et utilisés de manière polymorphe; regarde moi .[typical OO code] use new a lot
: peut-être dans un vieux livre, mais qui s'en soucie? Tousnew
les pointeurs C ++ vaguement modernes évitent / pointent dans la mesure du possible - et ne sont en aucun cas moins OO en le faisantUn point de plus pour toutes les bonnes réponses ci-dessus, cela dépend du type de programmation que vous faites. Développement du noyau sous Windows par exemple -> La pile est sévèrement limitée et vous ne pourrez peut-être pas accepter les défauts de page comme en mode utilisateur.
Dans de tels environnements, les appels d'API nouveaux ou similaires à C sont préférés et même requis.
Bien sûr, ce n'est qu'une exception à la règle.
la source
new
alloue des objets sur le tas. Sinon, les objets sont alloués sur la pile. Recherchez la différence entre les deux .la source