OVH Cloud OVH Cloud

delete []

39 réponses
Avatar
Jean-Marie Epitalon
Bonjour,

quelqu'un pourrait-il me dire à quoi sert les [] dans l'instruction delete
[] comme dans l'exemple suivant:

int * ma_table = new int[10];
...
delete [] ma_table;

Je me demande pourquoi on en a besoin car en langage C, quand on libère de
la mémoire, on passe un pointeur à la fonction free() et c'est tout....
Merci
Jean-Marie

9 réponses

1 2 3 4
Avatar
Michel Decima
Loïc Joly writes:

Le problèe est si une exception est lancée au moment de la construction de
la chaîne. Dans ce cas, rien n'a encore été affecté au shard_ptr, qui ne
pourra donc pas faire le ménage, et pourtant on a déjà alloué manuellement
de la mémoire pour la chaîne, qui ne sera jamais libérée.


Le compilateur doit normalement (*) generer du code qui appelle l'operateur
delete si une exception est lancee pendant l'execution d'un constructeur
appele par une expression new. Dans le cas de tableaux, les elements deja
construits doivent etre detruits.


C'est ce que je pensais aussi. Si ce n'etait pas le cas, le langage
devrait exiger des constructeurs T throw() pour la creation avec new...


Avatar
Loïc Joly
Loïc Joly writes:

Le compilateur doit normalement (*) generer du code qui appelle l'operateur
delete si une exception est lancee pendant l'execution d'un constructeur
appele par une expression new. Dans le cas de tableaux, les elements deja
construits doivent etre detruits.

On parlait du new avec placement, ce cas est le seul cas ou l'operateur
delete avec placement est appele automatiquement.

Je me demande si tu ne confonds pas le cas
f(new X, new Y);
ou un sequencement legal est
new X;
new Y;
constructeur du smart_ptr pour X,
constructeur du smart_ptr pour Y,
appel a f
ou effectivement une exception lancee par le constructeur de Y va liberer
la memoire allouee pour Y mais le X ne sera pas detruit ni sa memoire
liberee.


Oui, effectivement, je ne devais pas être bien réveillé (il était midi ?
Oui et ? ;)) Mais du coup, je ne vois plus trop où est le problème dont
parlait Laurent.

--
Loïc

Avatar
Jean-Marc Bourguet
Loïc Joly writes:

Mais du coup, je ne vois plus trop où est le problème dont parlait
Laurent.


Moi non plus. Enfin, je ne l'ai jamais bien vu.

A+

--
Jean-Marc

Avatar
Laurent Deniau
Jean-Marc Bourguet wrote:
Loïc Joly writes:


Mais du coup, je ne vois plus trop où est le problème dont parlait
Laurent.



Moi non plus. Enfin, je ne l'ai jamais bien vu.


Dans l'exemple donne par Loic, il n'y avait pas de probleme. Mais dans

C::C(size_t n) : myT(new T[n]) {}

si la construction d'un element de type T du tableau myT alloue de la
memoire puis leve une exception, la memoire allouee par cet element
incompletement construit ne sera par liberee, meme en presence d'un
auto_ptr et autre pointeur intelligent.

Sauf si on utilise un placement new qui pour la raison que tu as
mentionne, nous donnera la main dans son placement delete *avant* de
liberer la memoire du tableau. Bref, mieux vaut utiliser std::vector.

A propos de la question du PO, il est interessant de lire 12.5.7.

a+, ld.


Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Dans l'exemple donne par Loic, il n'y avait pas de probleme. Mais dans

C::C(size_t n) : myT(new T[n]) {}

si la construction d'un element de type T du tableau myT alloue de la
memoire puis leve une exception, la memoire allouee par cet element
incompletement construit ne sera par liberee, meme en presence d'un
auto_ptr et autre pointeur intelligent.

Sauf si on utilise un placement new qui pour la raison que tu as
mentionne, nous donnera la main dans son placement delete *avant* de
liberer la memoire du tableau.


Si une exception est jetée pendant un constructeur, les éléments
précédemment construits sont détruits et la mémoire du new[] est libérée.

Si on quite un constructeur par une exception après avoir alloué de la
mémoire sans s'assurer qu'elle sera détruite par un destructeur (d'une
classe de base, d'un membre, d'une variable automatique) ou qu'elle est
prise en charge par une variable globale, évidemment qu'il y a une fuite.
Mais elle est présente dans:

C::C() : myT(new T) {}

ou même dans

T myT;

Donc je ne comprends pas ta mention du placement new. Tu peux donner un
exemple complet et minimal?

Bref, mieux vaut utiliser std::vector.


Ça, je doute que quelqu'un dans le fil le conteste.

A propos de la question du PO, il est interessant de lire 12.5.7.


Je ne vois pas le rapport avec la question (le paragraphe 12.5.7 que j'ai
sous les yeux traite du fait que operateur delete qui est statique -- et
donc pas virtuel -- est cherché dans le scope de la classe qui est le type
dynamique de l'objet si le destructeur est virtuel; la question de l'OP
traite de la différence entre delete[] et delete).

A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
James Kanze
Jean-Marc Bourguet wrote:
Loïc Joly writes:


Est-ce que tu pourrais donner un exemple, parce que je ne
vois pas (encore) le probleme, a part le fait que si le
constructeur de T lance une exception, elle va se propager
a l'exterieur. Est-ce que c'est ca le niveau de safety,
cad le ctor ne provoque pas d'exception ?


Si on remplace double par string dans mon exemple, alors, le
new va allouer de la mémoire pour la chaîne, puis le
constructeur de la chaîne est appelé (qui fait ses propres
allocations mémoire), puis le résultat est passé au
constructeur du shared_ptr qui en prends alors la possession
et le détruira à la destruction de l'objet.

Le problèe est si une exception est lancée au moment de la
construction de la chaîne. Dans ce cas, rien n'a encore été
affecté au shard_ptr, qui ne pourra donc pas faire le
ménage, et pourtant on a déjà alloué manuellement de la
mémoire pour la chaîne, qui ne sera jamais libérée.


Le compilateur doit normalement (*) generer du code qui appelle l'operate ur
delete si une exception est lancee pendant l'execution d'un constructeur
appele par une expression new.


Si le constructeur *sort* par une exception, évidemment. Si
l'exception est attrappée dans le constructeur, il n'y a pas de
problème.

[...]
(*) J'ai le souvenir de cas ou il ne le fait pas mais je ne me souviens
plus des details et n'ai pas le temps de regarder. Ce que j'ai retenu est
qu'en comportement normal (en definissant toujours new et delete qui
correspond), il n'y a pas de problemes.


Je me rappelle de beaucoup de compilateurs qui ne le faisaient
pas. Il y a dix ans. (Évidemment, beaucoup d'entre eux ne
supportaient pas les exceptions de tout.)

Aujourd'hui, j'ai du mal à croire qu'il y a encore un problème.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
James Kanze
Laurent Deniau wrote:
James Kanze wrote:
tu ne fais jamais de new dans un ctor? Ou alors tu ne cherches pas a
ecrire du code 'exception safe'.


Un placement new, jamais. D'ailleurs, les new normaux dans le
corps d'un constructeur sont assez rare, précisement parce que
je tiens à être exception safe. (Quand j'y pense -- les new
tout court sont pas si fréquents. Ce n'est pas du Java, après
tout. Et dans un constructeur, il sont vraiment rare, en dehors
de l'idiome du pare-feu de compilation.)


Tout a fait. Je voulais juste profiter de l'occasion pour rappeler que
le seul moyen d'etre exception safe dans un constructeur qui utilise new
etait d'utiliser un 'placement new', histoire de decourager les
debutants d'utiliser new ;-)


Explique-toi, parce qu'il n'y pas de problème avec new dans un
constructeur que les new de placement pourrait résoudre.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Jean-Marc Bourguet
"James Kanze" writes:

Si le constructeur *sort* par une exception, évidemment. Si
l'exception est attrappée dans le constructeur, il n'y a pas de
problème.


Je me suis mal exprimé en effet.

[...]
(*) J'ai le souvenir de cas ou il ne le fait pas mais je ne me souviens
plus des details et n'ai pas le temps de regarder. Ce que j'ai retenu est
qu'en comportement normal (en definissant toujours new et delete qui
correspond), il n'y a pas de problemes.


Je me rappelle de beaucoup de compilateurs qui ne le faisaient
pas. Il y a dix ans. (Évidemment, beaucoup d'entre eux ne
supportaient pas les exceptions de tout.)


Je faisais allusion à 5.3.4/19

A declaration of a placement deallocation function matches the declaration
of a placement allocation function if it has the same number of parameters
and, after parameter transformations (8.3.5), all parameter types except
the first are identical. Any non-placement deallocation function matches a
non-placement allocation function. If the lookup finds a single matching
deallocation function, that function will be called; otherwise, no
deallocation function will be called.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Laurent Deniau
Jean-Marc Bourguet wrote:

Donc je ne comprends pas ta mention du placement new. Tu peux donner un
exemple complet et minimal?


Ben apres un week-end de break, je ne vois plus non plus de quel
probleme je voulais parler. Je soupconne avoir vu un probleme la ou il
n'y en avait pas ou avoir confondu avec autre chose. Peut-etre l'effet
'fin de semaine fatiguante' ;-)

A propos de la question du PO, il est interessant de lire 12.5.7.



Je ne vois pas le rapport avec la question (le paragraphe 12.5.7 que j'ai
sous les yeux traite du fait que operateur delete qui est statique -- et
donc pas virtuel -- est cherché dans le scope de la classe qui est le type
dynamique de l'objet si le destructeur est virtuel; la question de l'OP
traite de la différence entre delete[] et delete).


Oui, et c'est l'objet de ma remarque. Si j'ai bien compris 12.5.7 (qui
se base sur 5.3.5.3), il y a une difference de comportement fondamentale
entre delete et delete[] (question de l'OP). Lorsque le type statique ne
correspond pas au type dynamique (cas d'objet polymorphique avec
destructeur virtuel), Le premier autorise la destruction alors que le
second donne un UB. Je suppose que la raison est que comme il est
statique, il ne peut pas retrouver la taille d'un element via 'this' et
donc il ne sait pas de combien il faut avancer pour appliquer le
destructeur aux elements suivant le premier. Il me semble de memoire
qu'il y a une section dans le D&E qui detail tout ca.

a+, ld.


1 2 3 4