C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

'erase' et validité de l'itérateur

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Vincent Richard
Guest





PostPosted: Sat Aug 16, 2003 10:57 pm    Post subject: 'erase' et validité de l'itérateur Reply with quote



Bonjour,

Le code suivant est-il valide ?

std::vector <Objet*> v;

// ...

for (std::vector<Objet*>::iterator it = v.begin() ; it != v.end() ; ++it)
{
// On supprime tous les éléments '123' du vecteur
if ((*it)->valeur == 123)
{
Objet* const obj = *it;
v.erase(it);

// Appel d'une fonction pour notifier la suppression de l'élément
f(obj);
delete obj;

// PROBLEME : 'it' est-il toujours valide ici ??? Peut-on
// continuer à itérer ?
}
}

Et si non, comment faire ?

Merci d'avance pour vos réponses.

Vincent

--
SL> Au fait elle est mieux ma signature maintenant ?
Oui. T'enlève encore les conneries que t'as écrit dedans et c'est bon.
-+- JB in <http://www.le-gnu.net> : Le neuneuttoyage par le vide -+-
Back to top
Fabien LE LEZ
Guest





PostPosted: Sun Aug 17, 2003 2:30 am    Post subject: Re: 'erase' et validité de l'itérateur Reply with quote



On Sun, 17 Aug 2003 00:57:48 +0200, Vincent Richard
<chere-loque.MARRE-DE-LA-PUB (AT) wanadoo (DOT) fr.invalid> wrote:

Quote:
for (std::vector<Objet*>::iterator it = v.begin() ; it != v.end() ; ++it)
{
// On supprime tous les éléments '123' du vecteur
if ((*it)->valeur == 123)
{
Objet* const obj = *it;

J'aime pas le "const" ici. En effet, tu déclares ici un pointeur
constant vers un "Objet". Or l'appel à "delete" va transformer ce
pointeur en un pointeur invalide. Certes, le "const" est valide du
point de vue C++, mais il ne me paraît pas logique.

Quote:
v.erase(it);

// Appel d'une fonction pour notifier la suppression de l'élément
f(obj);
delete obj;

Perso, je mettrais "delete" avant "erase". Mais bon, ce n'est que mon
feeling ;-)

Quote:

// PROBLEME : 'it' est-il toujours valide ici ?

Non (du moins, ce n'est pas garanti).

Une solution est d'utiliser la valeur de retour de erase(), qui est
sensée être un itérateur sur l'élément suivant :

for (std::vector<Objet*>::iterator it = v.begin(); it != v.end()Wink
{
// On supprime tous les éléments '123' du vecteur
if ((*it)->valeur == 123)
{
Objet* const obj = *it;
..
it= v.erase(it);
}
else
{
++it;
}
}

Deux bémols toutefois :
- il est des implémentations de la STL pour lesquelles erase()
ne renvoie pas de valeur (celle de BC++ 5.02). Si tu n'utilises que
des compilateurs récents, ça ne devrait pas poser de problèmes, mais
garde ça à l'esprit en cas d'erreur de compilation lors d'un portage.
- std::vector<> est adapté pour des ajouts/suppressions à la
fin, et l'accès aléatoire. Il n'est pas du tout adapté à
l'insertion/suppression d'éléments au milieu : non seulement c'est
lent, mais en plus ça invalide tous les itérateurs. Si tu as beaucoup
de suppressions à faire (et pas d'accès aléatoire), je conseille
plutôt std::list<> :

for (std::list<Objet*>::iterator it = v.begin(); it != v.end()Wink
{
// On supprime tous les éléments '123' du vecteur
if ((*it)->valeur == 123)
{
Objet* const obj = *it;
..
v.erase(it++);
}
else
{
++it;
}
}


--
Tout sur fr.* (FAQ, etc.) : http://www.usenet-fr.net/fur/
et http://www.aminautes.org/forums/serveurs/tablefr.html
Archives : http://groups.google.com/advanced_group_search
http://www.usenet-fr.net/fur/usenet/repondre-sur-usenet.html

Back to top
Fabien LE LEZ
Guest





PostPosted: Sun Aug 17, 2003 9:33 am    Post subject: Re: 'erase' et validité de l'itérateur Reply with quote



On Sun, 17 Aug 2003 09:25:49 +0200, Vincent Richard
<chere-loque.MARRE-DE-LA-PUB (AT) wanadoo (DOT) fr.invalid> wrote:

Quote:
v.erase(it++);

Je suppose qu'ici, il faut lire :

it = v.erase(it);

Non : ce que j'avais écrit fonctionne avec std::list<> ; de plus, il
me semble que std::list<>::erase ne renvoie pas forcément un itérateur
sur l'élément suivant.


--
Tout sur fr.* (FAQ, etc.) : http://www.usenet-fr.net/fur/
et http://www.aminautes.org/forums/serveurs/tablefr.html
Archives : http://groups.google.com/advanced_group_search
http://www.usenet-fr.net/fur/usenet/repondre-sur-usenet.html

Back to top
Patrick Mézard
Guest





PostPosted: Sun Aug 17, 2003 9:42 am    Post subject: Re: 'erase' et validité de l'itérateur Reply with quote


Quote:
v.erase(it);

// Appel d'une fonction pour notifier la suppression de
l'élément
f(obj);
delete obj;

Perso, je mettrais "delete" avant "erase". Mais bon, ce n'est que mon
feeling Wink

Même si dans son exemple l'ordre n'a pas d'importance (à condition que le
destructeur de Objet ne lance pas d'exception), tu préfères conserver
(transitoirement) un élément invalide (car détruit) dans le conteneur avant
de le retirer, plutôt que de retirer un élément valide avant de le détruire
(quitte à risquer la fuite de mémoire) ?

Patrick Mézard




Back to top
Patrick Mézard
Guest





PostPosted: Sun Aug 17, 2003 12:52 pm    Post subject: Re: 'erase' et validité de l'itérateur Reply with quote

Quote:
Soit T un type quelconque

void g (T&);

vector<T> v= ...;
vector<T>::iterator it= ...;

A priori, je préfère l'écriture

g (*it);
v.erase (it);

à l'écriture

T temp (*it);
v.erase (it);
g (temp);

(quitte à risquer la fuite de mémoire) ?

Garder un pointeur sur lequel on a appelé delete peut éventuellement
générer un core dump et/ou un comportement indéfini si on le
déréférence, mais pas une fuite mémoire, puisque delete a été appelé.

Oui justement, en supposant que g() soit modifiante ET susceptible d'échouer
en laissant T dans un état non-valide (et potentiellement en balançant une
exception ou que sais-je), je préfère copier "it", le virer du conteneur,
puis le modifier, pour ne pas me retrouver avec un élement dans un état
indéterminé dans le conteneur.

Dans le cas soulevé par Vincent, tout cela est bien entendu surperflu car il
manipule des pointeurs (donc constructeur de copie et assignation en
throw(), donc erase() en throw()) et son destructeur ne lance bien sûr pas
d'exceptions donc on est tranquilles.

Patrick Mézard



Back to top
Fabien LE LEZ
Guest





PostPosted: Mon Aug 18, 2003 12:26 am    Post subject: Re: 'erase' et validité de l'itérateur Reply with quote

On Sun, 17 Aug 2003 14:52:13 +0200, "Patrick Mézard"
<patrick.mezard (AT) ifrance (DOT) com> wrote:

Quote:
Oui justement, en supposant que g() soit modifiante ET susceptible d'échouer
en laissant T dans un état non-valide (et potentiellement en balançant une
exception ou que sais-je), je préfère copier "it", le virer du conteneur,
puis le modifier, pour ne pas me retrouver avec un élement dans un état
indéterminé dans le conteneur.

Mais une fonction g() vraiment exception-safe doit :
- soit nettoyer correctement l'objet et retourner normalement ;
- soit laisser l'objet sans modification et lancer une
exception.

Exemple :

void g (Objet* &o)
{
if (o.OnPeutSupprimer() == false)
{
throw "Supression impossible";
}
/* Eventuellement ici, un code qui ne peut pas lancer d'exception */
delete o;
}

Si tu as un objet dans un état indéfini, le code ne peut pas avoir un
comportement défini de toutes façons :
- soit tu l'enlèves du conteneur, avec un risque de fuite
mémoire ;
- soit tu le laisses dans le conteneur, avec un risque
d'utiliser un objet invalide.



--
Tout sur fr.* (FAQ, etc.) : http://www.usenet-fr.net/fur/
et http://www.aminautes.org/forums/serveurs/tablefr.html
Archives : http://groups.google.com/advanced_group_search
http://www.usenet-fr.net/fur/usenet/repondre-sur-usenet.html

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.