148 votes

Comment supprimer[] savez que c'est un tableau?

Bon, je pense que nous sommes tous d'accord que ce qui se passe avec le code suivant n'est pas défini, en fonction de ce qui est passé,

void deleteForMe(int* pointer)
{
     delete[] pointer;
}

Le pointeur peut être toutes sortes de choses différentes, et donc d'effectuer un inconditionnel delete[] sur il n'est pas défini. Cependant, supposons que nous sommes, en effet, le passage d'un tableau de pointeur,

int main()
{
     int* arr = new int[5];
     deleteForMe(arr);
     return 0;
}

Ma question est, dans ce cas où le pointeur est un tableau, qui est-ce qui sait? Je veux dire, de la langue/du compilateur point de vue, il n'a aucune idée de savoir si ou non arr est un tableau de pointeur par rapport à un pointeur vers un seul int. Heck, il ne sait même pas si arr a été créé de façon dynamique. Pourtant, si je ne les suivants au lieu de cela,

int main()
{
     int* num = new int(2);
     deleteForMe(num);
     return 0;
}

L'OS est assez intelligent pour ne supprimez un int et ne pas aller sur un certain type de "tuerie" en supprimant le reste de la mémoire au-delà de ce point (contrairement à strlen et un non-\0chaîne terminée -- il va continuer jusqu'à ce qu'il arrive à 0).

Donc dont le travail est-il un souvenir de ces choses? L'OS de garder un certain type de l'enregistrement en arrière plan? (Je veux dire, je me rends compte que j'ai commencé ce post en disant que ce qui se passe n'est pas défini, mais le fait est, la "tuerie" scénario ne se produise pas, donc, par conséquent, dans la pratique , quelqu'un s'en rappelle.)

114voto

Dan Breslau Points 9217

Une question que les réponses apportées jusqu'à présent ne semblent pas à l'adresse: si les bibliothèques d'exécution (pas de l'OS, vraiment) peuvent garder une trace du nombre de choses dans le tableau, alors pourquoi avons-nous besoin de l' delete[] de la syntaxe? Pourquoi pas un seul delete , le formulaire doit être utilisé pour gérer toutes les supprime?

La réponse à cela remonte à C++de racines comme un C-compatible de la langue (ce qui n'est plus vraiment s'efforce de l'être.) De Stroustrup philosophie est que le programmeur ne devrait pas avoir à payer pour des fonctionnalités qu'ils n'utilisent pas. Si ils ne sont pas à l'aide de tableaux, alors qu'ils ne devraient pas avoir à porter le coût de tableaux d'objets pour chaque alloué partie de la mémoire.

C'est, si votre code ne fonctionne tout simplement

Foo* foo = new Foo;

ensuite, l'espace de la mémoire allouée pour l' foo ne comprennent pas les frais généraux supplémentaires qui seraient nécessaires à l'appui des tableaux de Foo.

Car seul tableau dotations sont mis en place pour effectuer la taille de la matrice extra d'informations, vous devez ensuite indiquer au runtime des bibliothèques de chercher cette information lorsque vous supprimez les objets. C'est pourquoi nous avons besoin d'utiliser

delete[] bar;

au lieu de simplement

delete bar;

si la barre est un pointeur sur un tableau.

Pour la plupart d'entre nous (moi y compris), que la vanité de quelques octets supplémentaires de mémoire semble pittoresques de ces derniers jours. Mais il existe toujours des situations où économiser quelques octets (de ce que pourrait être un très grand nombre de blocs de mémoire) peut être important.

105voto

Fred Larson Points 27404

Le compilateur ne sait pas c'est un tableau, c'est de faire confiance au programmeur. La suppression d'un pointeur à un seul type int avec delete [] entraînerait un comportement indéfini. Votre deuxième main() par exemple est dangereux, même si elle n'est pas immédiatement crash.

Le compilateur ne devez garder une trace de la façon dont de nombreux objets doivent être supprimés en quelque sorte. Il peut le faire par la sur-allouer suffisamment de mémoire pour stocker la taille de la matrice. Pour plus de détails, consultez la FAQ Lite.

31voto

bsdfish Points 1340

Oui, l'OS garde certaines choses dans le "background". Par exemple, si vous exécutez

int* num = new int[5];

le système d'exploitation peut allouer 4 octets supplémentaires, magasin de la taille de l'allocation dans les 4 premiers octets de la mémoire allouée et retourner un pointeur décalé (c'est à dire, il alloue de la mémoire, des espaces de 1000 à 1024, mais le pointeur retourné points à 1004, avec des emplacements 1000-1003 le stockage de la taille de l'allocation). Puis, lorsque la suppression est appelé, il peut regarder 4 octets avant le pointeur est passé pour trouver la taille de l'allocation.

Je suis sûr qu'il y a d'autres façons d'assurer le suivi de la taille d'une allocation, mais c'est une option.

13voto

JaredPar Points 333733

Ceci est très similaire à cette question et il a beaucoup de détails que vous cherchez.

Mais il suffit de dire, il n'est pas le travail de l'OS de suivre n'importe quelle de ce. C'est en fait le moteur d'exécution ou dans les bibliothèques, sous-jacent gestionnaire de mémoire qui leur permettra de suivre la taille de la matrice. Cela se fait généralement par l'allocation de la mémoire supplémentaire à l'avant et le stockage de la taille de la matrice à cet endroit (la plupart d'utiliser un nœud de tête).

Ceci est visible sur certaines implémentations en exécutant le code suivant

int* pArray = new int[5];
int size = *(pArray-1);

6voto

eduffy Points 17061

Il ne sait pas c'est un tableau, c'est pourquoi vous devez vous approvisionner en delete[] au lieu d'un vieux - delete.

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