Question

C’est une question qui me harcèle depuis quelque temps. J'ai toujours pensé que C ++ aurait dû être conçu de manière à ce que "& supprime" opérateur (sans crochets) fonctionne même avec le "nouveau []" opérateur.

À mon avis, en train d'écrire ceci:

int* p = new int;

devrait être équivalent à l'allocation d'un tableau de 1 élément:

int* p = new int[1];

Si cela est vrai, la fonction "supprimer" L’opérateur peut toujours supprimer des tableaux et nous n’aurions pas besoin de l’option " delete [] " opérateur.

Existe-t-il une raison quelconque pour laquelle l'option " delete [] " opérateur a été introduit en C ++? La seule raison pour laquelle je peux penser est que l'allocation de tableaux a un faible encombrement mémoire (vous devez stocker la taille du tableau quelque part), de sorte que la distinction "supprimer" vs " delete [] " était une petite optimisation de la mémoire.

Était-ce utile?

La solution

C’est pour que les destructeurs des éléments individuels soient appelés. Oui, pour les tableaux de POD, il n'y a pas beaucoup de différence, mais en C ++, vous pouvez avoir des tableaux d'objets avec des destructeurs non triviaux.

Maintenant, votre question est la suivante: pourquoi ne pas créer nouveau et supprimer se comporter comme nouveau [] et supprimer [] et se débarrasser de new [] et de delete [] ? Je reviendrais sur "Design and Evolution" de Stroustrup livre où il a dit que si vous n'utilisez pas les fonctionnalités C ++, vous ne devriez pas les payer (au moins au moment de l'exécution). En l'état actuel des choses, un nouveau ou un delete se comportera aussi efficacement que malloc et libre . Si delete avait la signification delete [] , il y aurait une surcharge supplémentaire au moment de l'exécution (comme l'a souligné James Curran).

Autres conseils

Zut, j'ai raté toute la question, mais je vais laisser ma réponse originale en sidenote. La raison pour laquelle nous avons delete [], c’est qu’il ya longtemps que nous avions delete [cnt]. Même aujourd’hui, si vous écrivez delete [9] ou delete [cnt], le compilateur ignore tout ce qui se trouve entre [] mais compile bien. A cette époque, le C ++ était d'abord traité par un frontal, puis transmis à un compilateur C ordinaire. Ils ne pouvaient pas faire le tour de stocker le compte quelque part sous le rideau, peut-être qu'ils ne pouvaient même pas y penser à ce moment-là. Et pour la compatibilité ascendante, les compilateurs ont probablement utilisé la valeur donnée entre [] comme nombre de tableaux. S'il n'y en a pas, ils ont obtenu le nombre à partir du préfixe, ce qui a fonctionné dans les deux sens. Plus tard, nous n’avons rien saisi entre [] et tout a fonctionné. Aujourd'hui, je ne pense pas que "supprimer [] " est nécessaire mais les implémentations l'exigent ainsi.

Ma réponse originale (ça manque le point) ::

" supprimer " supprime un seul objet. "supprimer [] " supprime un tableau d'objets. Pour que delete [] fonctionne, l'implémentation conserve le nombre d'éléments dans le tableau. Je viens de vérifier cela en déboguant du code ASM. Dans l’implémentation (VS2005) que j’ai testée, le compte était stocké comme préfixe du tableau d’objets.

Si vous utilisez " delete [] " sur un seul objet, la variable count est un déchet, de sorte que le code se bloque. Si vous utilisez " supprimer " pour un tableau d'objets, à cause d'une certaine incohérence, le code se bloque. J'ai testé ces cas tout à l'heure!

"delete" supprime simplement la mémoire allouée au tableau. " déclaration dans une autre réponse n'est pas juste. Si l'objet est une classe, delete appellera le DTOR. Il suffit de placer un point d'arrêt dans le code DTOR et de supprimer l'objet. Le point d'arrêt apparaîtra.

Ce qui m’est venu à l’esprit, c’est que, si le compilateur & amp; Les bibliothèques supposaient que tous les objets alloués par " new " sont des tableaux d'objets, vous pouvez appeler " delete " pour des objets simples ou des tableaux d'objets. Un seul objet serait juste le cas particulier d’un tableau d’objets ayant un compte de 1. Peut-être qu’il me manque quelque chose, de toute façon ...

Puisque tout le monde semble avoir oublié le sens de votre question, j'ajouterai simplement que j'avais la même pensée il y a un an et que je n'ai jamais pu obtenir de réponse.

La seule chose à laquelle je peux penser, c’est qu’il existe un très petit supplément de temps système qui permet de traiter un seul objet comme un tableau (inutile "& code; pour> int (= i; 0; i < 1; ++ i ) ")

Ajouter ceci car aucune autre réponse ne l'aborde actuellement:

Le tableau delete [] ne peut jamais être utilisé sur une classe pointeur vers base - pendant que le compilateur enregistre le nombre d'objets lorsque vous appelez new [] , il ne stocke pas les types ou les tailles des objets (comme l'a souligné David, en C ++, vous payez rarement pour une fonctionnalité que vous n'utilisez pas). Cependant, code scalaire peut être supprimé en toute sécurité via la classe de base. Il est donc utilisé à la fois pour le nettoyage d'objet normal et le nettoyage polymorphe:

struct Base { virtual ~Base(); };
struct Derived : Base { };
int main(){
    Base* b = new Derived;
    delete b; // this is good

    Base* b = new Derived[2];
    delete[] b; // bad! undefined behavior
}

Cependant, dans le cas contraire - destructeur non virtuel - scalaire delete devrait être aussi économique que possible - il ne devrait pas vérifier le nombre d'objets, ni le type d'objet en cours. supprimé. Cela rend la suppression d'un type intégré ou d'un type de données ordinaire très ancien très économique, car le compilateur n'a qu'à appeler :: operator delete et rien d'autre:

int main(){
    int * p = new int;
    delete p; // cheap operation, no dynamic dispatch, no conditional branching
}

Bien que le traitement de l'allocation de mémoire ne soit pas exhaustif, j'espère que cela contribuera à clarifier l'étendue des options de gestion de la mémoire disponibles en C ++.

Marshall Cline a des informations sur ce sujet .

delete [] garantit que le destructeur de chaque membre est appelé (si applicable au type) tandis que delete supprime simplement la mémoire allouée pour le tableau.

En voici une bonne lecture: http: //www.informit. com / guides / content.aspx? g = cplusplus & amp; seqNum = 287

Et non, les tailles de tableau ne sont stockées nulle part en C ++. (Merci à tous d'avoir souligné que cette déclaration est inexacte.)

La réponse d'Aaron me laisse un peu perplexe et admet franchement que je ne comprends pas tout à fait pourquoi et où supprimer [] est nécessaire.

J'ai fait quelques expériences avec son exemple de code (après avoir corrigé quelques fautes de frappe). Voici mes résultats.     Typos: ~ Base avait besoin d'un corps de fonction     La base * b a été déclarée deux fois

struct Base { virtual ~Base(){ }>; };
struct Derived : Base { };
int main(){
Base* b = new Derived;
delete b; // this is good

<strike>Base</strike> b = new Derived[2];
delete[] b; // bad! undefined behavior
}

Compilation et exécution

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
david@Godel: # No error message

Programme modifié avec supprimer [] supprimé

struct Base { virtual ~Base(){}; };
struct Derived : Base { };

int main(){
    Base* b = new Derived;
    delete b; // this is good

    b = new Derived[2];
    delete b; // bad! undefined behavior
}

Compilation et exécution

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
atest(30746) malloc: *** error for object 0x1099008c8: pointer being freed was n
ot allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Bien sûr, je ne sais pas si delete [] b fonctionne réellement dans le premier exemple; Je sais seulement que cela ne donne pas un message d'erreur du compilateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top