OVH Cloud OVH Cloud

raisons d'une erreur avec delete?

6 réponses
Avatar
olivier.faust
Bonjour,

j'ai un probleme d'utilisation de delete avec un objet map. Mon code
est peu trop gros, donc je vais essayer de vous expliquer clairement la
situation :

J'ai un objet que j'appelle P. Je cr=E9e avec new, dans cette objet, un
objet de classe A. Pour =EAtre pr=E9cis, je cr=E9e dans P une map de type
: map<int,A*>. Donc chaque A cr=E9=E9 est tout de suite class=E9 dans
cette map. Je triture tout =E7a dans tous les sens, puis quand j'ai fini
de m'amuser, je souhaite d=E9truire le tout.

donc je fais mon delete P; qui appelle le destructeur de A. Jusqu'ici
tout va bien.

Soit : map<int,A*> aMap; la map contenant les A que je souhaite
d=E9truire, pour d=E9truire, j'utilise delete. Je fais une boucle :
for(int i=3D0; i=3Dtaille de la map; i++)
{
delete aMap[i];
}

et l=E0, segmentation fault. Sachant que si je compare &aMap[0] juste
apr=E8s sa cr=E9ation et juste avant sa destruction, j'obtiens la m=EAme
valeur...

Donc si vous avez une id=E9e d'o=F9 pourrait venir l'erreur, toutes vos
suggestions sera tr=E8s appr=E9ci=E9e :o)

6 réponses

Avatar
Michel Decima
Soit : map<int,A*> aMap; la map contenant les A que je souhaite
détruire, pour détruire, j'utilise delete. Je fais une boucle :
for(int i=0; i=taille de la map; i++)
{
delete aMap[i];
}


Ne serait il pas plus judicieux d'utiliser des iterateurs pour la boucle ?

map<int,A*>::iterator it_end = aMap.end();
for (map<int,A*>::iterator it = aMap.begin(); it != it_end; ++it)
{
delete it->second;
}

Avatar
Cyrille
Bonjour,

j'ai un probleme d'utilisation de delete avec un objet map. Mon code
est peu trop gros, donc je vais essayer de vous expliquer clairement la
situation :

J'ai un objet que j'appelle P. Je crée avec new, dans cette objet, un
objet de classe A. Pour être précis, je crée dans P une map de type
: map<int,A*>. Donc chaque A créé est tout de suite classé dans
cette map. Je triture tout ça dans tous les sens, puis quand j'ai fini
de m'amuser, je souhaite détruire le tout.

donc je fais mon delete P; qui appelle le destructeur de A. Jusqu'ici
tout va bien.

Soit : map<int,A*> aMap; la map contenant les A que je souhaite
détruire, pour détruire, j'utilise delete. Je fais une boucle :
for(int i=0; i=taille de la map; i++)
{
delete aMap[i];
}


Là, il faut que tous les entiers de 0 à "taille de la map" soient
présents dans votre map. Si ce n'est pas le cas, vous aurez des 'i' pour
lesquels aMap[i] ne correspondra pas à quelque chose que vous avez
alloué, donc vous ferez probablement un delete sur une zone-mémoire qui
ne vous appartient pas ou qui n'existe pas et donc ça fera kaboum.

Je vous propose plutôt de parcourir votre map ainsi:

for ( map<int, A*::iterator it = aMap.begin(); it != aMap.end(); ++it )
{
delete it->second;
}

Comme ça vous enlèverez seulement ce qui est présent dans la map.

Autre possibilité, qui évite de faire une boucle de delete, utiliser
boost::shared_ptr<>:

map<int, boost::shared_ptr<A> > aMap;

Ainsi il suffit d'utiliser aMap::clear() pour détruire tous les
boost::shared_ptr<A> qui, dans leur destructeur, s'occuperont de faire
chacun un delete sur l'objet A sur lequel ils pointent respectivement.

--
"Kill Them All!" ~ Mohandas Karamchand "Mahatma" Gandhi

Avatar
kanze
Michel Decima wrote:
Soit : map<int,A*> aMap; la map contenant les A que je souhaite
détruire, pour détruire, j'utilise delete. Je fais une boucle :
for(int i=0; i=taille de la map; i++)
{
delete aMap[i];
}


Ne serait il pas plus judicieux d'utiliser des iterateurs pour
la boucle ?

map<int,A*>::iterator it_end = aMap.end();
for (map<int,A*>::iterator it = aMap.begin(); it != it_end; ++it)
{
delete it->second;
}


Juste un point de détail, mais formellement, ça donne un
comportement indéfini -- après le delete, le pointeur n'est
(officiellement, en tout cas) plus copiable, ce qui viole les
contraits des collections.

Dans la pratique, évidemment, ça ne donnerait jamais de
problèmes. Mais pour être 100% conforme, il faudrait quelque
chose comme :

template< typename T >
struct Deleter
{
void operator()( T*& p ) const
{
T* tmp = p ;
p = NULL ;
delete tmp ;
}
} ;

avec ensuite :

std::for_each( aMap.begin(), aMap.end(), Deleter< A >() ) ;

--
James Kanze GABI Software
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
Michel Decima
"kanze" a écrit dans le message de
news:

map<int,A*>::iterator it_end = aMap.end();
for (map<int,A*>::iterator it = aMap.begin(); it != it_end; ++it)
{
delete it->second;
}

Juste un point de détail, mais formellement, ça donne un
comportement indéfini -- après le delete, le pointeur n'est
(officiellement, en tout cas) plus copiable, ce qui viole les
contraits des collections.


Je ne savais pas qu'un pointeur n'est plus copiable apres delete.

Dans la pratique, évidemment, ça ne donnerait jamais de
problèmes. Mais pour être 100% conforme, il faudrait quelque
chose comme :

template< typename T >
struct Deleter
{
void operator()( T*& p ) const
{
T* tmp = p ;
p = NULL ;
delete tmp ;
}
} ;

avec ensuite :

std::for_each( aMap.begin(), aMap.end(), Deleter< A >() ) ;


Pour des container associatifs, ca ne va pas marcher directement,
mais je vois l'idee.

Avatar
Vincent Cantin
Donc si vous avez une idée d'où pourrait venir l'erreur, toutes vos
suggestions sera très appréciée :o)

<Troll>L'erreur vient du choix de la lib (et du language). J'ai jamais de
problemes comme ca avec Java.</Troll>

<Serieusement>Peut-etre que quelque part tu delete 2 fois sur tes pointeurs,
donc la deuxieme fois il ne comprend pas ce que tu fais et BOUM ..
casse.</Serieusement>
Avatar
Fabien LE LEZ
On Sat, 11 Mar 2006 11:25:07 +0800, "Vincent Cantin"
:

<Troll>L'erreur vient du choix de la lib (et du language). J'ai jamais de
problemes comme ca avec Java.</Troll>


La différence n'est pas tellement due au langage, mais à la présence
d'un garbage collector. Il n'y en a pas par défaut en C++, mais on
peut en mettre un si on fait beaucoup d'allocations dynamiques.