Pile vs Tas de C++
J'avais juste une question rapide sur la façon de pile variables en fonction de tas de variables de travail. Si je comprends bien, pile les variables sont des variables qu'après le retour des fonctions seront supprimés, et des tas de variables sont persistantes. Mais ce que je suis vraiment confus au sujet est de savoir comment allouer des tas de variables à l'intérieur des fonctions:
int MyObject::addObject(const char* a){
MyObject newObject(a);
return 0;
}
Dire que j'ai un constructeur pour MyObject
qui est newObject(const char * a)
. Ensuite, dans cette fonction, lorsqu'elle est appelée, après le retour n'est nouvellement construit newObject
supprimés? Si oui, comment pouvez-vous attribuer le tas à l'intérieur d'une fonction, alors? Si non, comment faites-vous le nettoyage de votre mémoire plus tard?
En outre, quel est exactement le rôle d'un destructeur et quand est-il appelé?
- Avez-vous envisagé d'utiliser des std::string à la place de char* ? Jetant C gestion de la mémoire dans le mélange a tendance à confondre, votre MyObject classe doit maintenant décider de comment est propriétaire de la mémoire pour le pointeur et très probablement besoin de copier la chaîne et d'un destructeur de le libérer à nouveau. Ne pas le faire, c'est très probablement chemin à l'échec.
- Vous ne devriez même pas penser à propos de "pile" et "tas". Quand vous conduisez une voiture, vous n'avez généralement pas à propos de cylindre cycle de modèles, pensez-vous? Les choses pour les comprendre en C++ sont les classes de stockage et durée de vie des objets: automatique (étendue), dynamique (manuel), statique (global).
- Lors de la nouvelle C ou C++, seriez-vous d'accord qu'il est bon de connaître la différence entre les deux? Je pense que c'est ce que l'OP est ici.
- Je dirais que c'est distrayant et trompeur de même considérer les deux. Ceux-ci sont un détail de l'implémentation que vous pouvez méditer sur un dimanche pluvieux autour d'un café, mais pour les fins de compréhension, C++, ils sont inutiles, et le bruit... surtout lorsque vous êtes nouveau et d'autre part la plus importante des choses à apprendre 🙂
- Quelle coïncidence, c'est dimanche et il pleut. Le café coule.
- SB, fortement en désaccord. Savez-vous que la taille de pile par défaut sur Windows 32 bits est de 1 mo? Si le novice ne sait pas, d' (s), il peut penser, cool, je vais utiliser la pile, tout le temps, mais vous ne devriez vraiment pas faire cela.
- Je dirais que c'est un algorithme qui utilise beaucoup la taille de la pile peut avoir d'autres problèmes. Bien sûr, il ya des situations où vous avez juste besoin d'une partie de la mémoire (dans ce cas, vous devriez baisse-dans le remplacement d'un
std::unique_ptr<Foo[]>
), mais ce devrait être une exception rare. - J'ai trop pas d'accord. Ce ne sont pas des détails de mise en œuvre, ce sont les concepts que vous devez comprendre, pour les mêmes raisons que les Classes et les Objets sont des concepts dans un langage de programmation orientée objet, et vous devriez le comprendre ainsi. Si vous ne savez pas où vos objets et la durée de vie de ceux-ci, vous n'allez pas être en mesure d'écrire efficace de code c++. Pas dans l'état actuel de la langue est au moins. Il ya seulement tellement que vous pouvez vous en sortir en juste à gratter la surface.
Vous devez vous connecter pour publier un commentaire.
Un constructeur de la classe
MyObject
estMyObject()
, pasnewObject()
. Dans votre exemple,newObject
est le nom de votre variable, pas le constructeur.À allouer sur le tas à l'intérieur d'une fonction, vous devez appeler le
new
opérateur:Votre code:
crée un stockage automatique (pile)
MyObject
appelénewObject
qui vit jusqu'à ce que le champ d'application il a été déclaré dans les fins - c'est à dire la fermeture}
.Pour nettoyer la mémoire de la classe allouée à
new
ounew[]
(oumalloc
) et qu'il possède. Elle est appelée lorsque l'objet est hors de portée automatique des objets, ou lorsque vous appelez explicitementdelete
pour les objets dynamiques.new
De la pile de la mémoire est ce que vous avez dit, mais pour être plus précis, c'est la mémoire locale du champ d'application actuel. Notez qu'en fonction de ce champ dont vous parlez, cette mémoire peut être global ou peut-être locale à une fonction ou d'une classe. Ce sont nettoyés une fois ils sont allés hors de portée.
De segment de mémoire allouée par le
new
de l'opérateur.Ces persistera en mémoire, même après tous les pointeurs pointant vers la mémoire sont allés hors de portée. Vous devez libérer explicitement cette mémoire vous-même en C++ via
delete
. Ne pas le faire va entraîner une fuite de mémoire, à moins que des pointeurs intelligents sont utilisés.Une autre chose à noter, prendre l'exemple de code suivant:
le pointeur lui-même, d'un bar, est créé sur la pile. Toutefois, les données pointées par la barre. *bar -- oui, l'astérisque ne faire une différence ici. Il vous obtient les données pointé par le pointeur-est sur le tas. Lorsque toto revient, la barre passe hors de portée. N'avais-je pas appelé supprimer, j'aurais perdu l'accès à l' *bar et aurait obtenu une fuite de mémoire.
Pour la deuxième question, le rôle de la dtor est de nettoyer l'objet que vous avez construit. L'un est fourni par défaut pour vous, mais il ya des moments où vous devez écrire votre propre. Par exemple, si votre classe a cru pointeurs, vous devez explicitement mise en liberté supprimer dans la dtor. Elle est appelée lorsque l'objet est hors de portée pour la pile de la mémoire et lors de la suppression est appelé à la mémoire du tas.
Ce code attribue newObject sur la pile. Il est construit (MyObject constructeur est appelé sur un morceau de la mémoire de pile) lors de la saisie de la fonction. C'est reutilisable (MyObject destructeur appelé sur cette instance) lorsque la fonction retourne juste avant la partie de la mémoire est sorti de la pile.
Ce code alloue un objet sur le tas. Le constructeur est appelé par l'opérateur new, après il est affecté certains de segment de mémoire. La mémoire n'est pas libérée et le destructeur n'est pas appelé jusqu'à ce que vous avez explicitement dire que vous avez terminé avec le mot clé delete.
Cela peut être n'importe où vous voulez dans votre programme.
foo
? Où vit-il? Comment est-il géré?La pile est une zone qui est utilisée dans la fonction et les appels de méthode. Il est essentiellement utilisé pour stocker les paramètres et la fonction des données locales (entre autres impliqué dans le processus de l'appel d'une fonction). La pile est une LIFO type de structure de données, ce qui signifie que la dernière chose que vous mettez en est la première fois que vous obtenez à partir d'elle.
Le tas, en revanche, est un magasin libre, j'entends par là que vous pouvez obtenir toutes les valeurs dans le tas peu importe l'ordre qu'il a mis là - cette distinction est importante.
En C++ , chaque fois que vous appelez
new
l'objet est créé sur le Tas et un pointeur vers cet objet est retourné à vous, vous pouvez utiliser le pointeur pour accéder à votre objet. Qui s'applique à la fois des objets complexes comme des objets de classes que vous ou quelqu'un d'autre a créé et construit dans les types, tels que int, char, double, etc... Il n'y a rien de magique avec l'aide de nouveau, il est à la base il appelle simplementmalloc
, ou certains saveur de celle-ci en fonction de la plate-forme, puis appelle le constructeur de l'objet. Vous devez penser à appelerdelete
(oudelete []p_array_of_object_pointers
) pour chaque objet créé avecnew
.Le destructeur n'est rien de plus qu'une fonction de la langue des appels sur l'objet lorsque vous faites un
delete my_object_pointer
dans votre code. Le destructeur vous donne une chance de faire un peu de ménage dans votre code. Dans des langages tels que C++, où vous devez gérer vos propres ressources, vous devez généralement utiliser pour appeler desdelete
oufree
sur d'autres objets que vous avez alloué sur le tas, ou de la fermeture des descripteurs de fichiers que vous avez créés avec fopen ou tel...Les deux mots-clés à travailler à l'intérieur ou à l'extérieur de fonctions et de méthodes, il n'importe pas où vous les appelez, ils seront toujours travailler avec le tas. Tout ce que vous créez sans l'utilisation de
new
le mettre dans un autre lieu, soit la zone statique de l'exécutable ou de la pile, en fonction de comment et où il est en cours de création.Chaque fois que vous créez un objet à l'intérieur d'une méthode ou d'une fonction avec la syntaxe suivante
MyClassType myObject(contructor, arguments);
et sans l'utilisation denew
, de sa création sur la pile (à moins que vous déclarez comme statique, ce qui est quand il se termine dans la zone statique je l'ai mentionné ci-dessus).Espère que cette aide.
tas allocations sont faites avec le
new
mot-cléC++ n'a pas de collecte des ordures, les allocations de tas ne sont jamais automatiquement libéré
vous pouvez libérer avec la
delete
mot-clévous avez besoin de garder un pointeur pour que, par exemple en retournant à partir de la fonction, ou de l'affecter à une variable globale
les destructeurs sont appelés
delete
et sont utilisées pour libérer des ressources, par exemple les sockets réseaude sorte que le code serait, par exemple
return new MyObject("foo");
Allouer de la mémoire dans la pile dans votre exemple. C'est variable automatique et il serait supprimé, puis le retour s'est passé.
Si vous utilisez
new
mot-clé, vous devez fournir le bon de libération de la mémoireComment allouer au tas: utilisation
new
mot-cléComment libérer de segment de mémoire: l'utilisation
delete
mot-clé.Pour éviter que le programme ne s'écraser et les fuites de mémoire, chaque
new
doit avoir sondelete
homologue pour l'objet spécifié et le type.Destructeur est appelé lorsque l'objet est supprimé, indépendamment de l'endroit où il a été stocké(tas, pile, ...)
Et voici des informations plus spécifiques sur la mémoire: Quoi et où sont de la pile et le tas?
Utilisation allouée dynamiquement des instances d'objets lors de l':
1) Le type réel de l'objet n'est pas connu au moment de la compilation
2) Lorsque le nombre d'objets que vous souhaitez créer, n'est pas connu au moment de la compilation
3) Lorsque le (généré par le compilateur) gestion de durée de vie de vos objets ne répondent pas à vos besoins.
Chaque objet créé avec l'opérateur new, doit être libérée avec opérateur d'effacement à un certain moment. Si vous ne le faites pas, vous aurez des fuites de mémoire, et si vous comptez sur les effets secondaires des objets destructeur, vous n'obtiendrez pas ces effets secondaires et votre programme ne peut pas faire ce qu'il veut faire.
Lorsqu'un objet est créé comme une pile variable, le compilateur va ajouter du code pour appeler les objets destructeur lorsque l'objet est hors de portée. Comment le compilateur de savoir ce destructeur de l'appeler? Le type de l'objet est connu au moment de la compilation, il y a seulement une possibilité, qu'un seul destructeur d'appel.
Si vous utilisez la "supprimer" pour détruire un objet, le compilateur ne peut pas être en mesure de dire qui de destructeur à utiliser. L'objet peut être de type "basique", puis le destructeur de base::~base () sera appelée.
Le compilateur ne sait pas le type réel de l'objet n'est pas 'de base', mais 'dérivé'. Si, toutefois, vous devez déclarer le destructeur de "base" pour être virtuel, le compilateur va insérer le code consulte les objets de la table de méthode virtuelle, et l'appel est redirigé vers la droite destructeur (dans ce cas, le destructeur qui détruit sur l'objet de type 'dérivé').
Si vous êtes inquiet à propos de ce problème, et si vous le pouvez, prenez le destructeur "virtuel".