2008-10-20 17 views
3

Supposons que j'ai un hash_map et un code commeQu'est-ce qu'un équivalent sécurisé d'effacement de STL non-nul?

// i is an iterator 
i = hash_map.erase(i) 

Mais STL de GCC ne retourne pas iterator en effacement, mais un vide. Il est maintenant un code comme

hash_map.erase(i++) 

sécurité (à savoir ne pas invalide iterator ou tout autre fait des choses inattendues ou désagréables)? S'il vous plaît noter que ceci est un hash_map.

Répondre

5

Oui, ceci est sûr, car la valeur de i aura été définie à la valeur suivante, avant que la valeur actuelle ne soit effacée.

Selon l'SGI documentation about hashed containers invalidation ne se produit pas pour les éléments non effacés, ni même pour le redimensionnement (il n'y a pas de mot sur si les insertions provoquent redimensionnement, donc pour faire attention je admets que comme une possibilité) --- mais dans le Dans ce dernier cas, l'ordre d'itération sera modifié. Mais cela ne s'applique pas ici, à moins que vous ne fassiez tout votre possible pour redimensionner le conteneur pendant la traversée ou autre chose. :-)

+0

Pouvez-vous indiquer où vous avez lu cela? Cela est vrai pour les conteneurs associatifs tels que définis dans l'ISO C++, mais je ne lis jamais rien de tel dans la documentation SGI. – PierreBdR

+1

C'est sur cette page liée à dans mon message. Je suppose, pour ce site, qu'à moins d'indication contraire, les opérations ne provoquent pas l'invalidation. Voir http://www.sgi.com/tech/stl/Vector.html (par exemple) où tous les cas d'invalidation sont mentionnés. –

+0

(J'ai choisi le vecteur spécifiquement parce que c'est un type de données qui a (apparemment) plus de cas d'invalidation que n'importe quel autre.) –

-4

Haine de pluie sur le défilé, mais je ne pense pas que ce que vous proposez est sûr.

i ++ est l'opérateur de post-incrémentation, ce qui signifie que i est incrémenté après l'appel à effacer. Mais l'effacement invalide tous les itérateurs pointant vers l'élément en cours d'effacement. Donc, au moment où i est incrémenté, il n'est plus valide.

Si vous êtes chanceux, il peut fonctionner correctement par accident jusqu'à un jour il ne fonctionne plus.

Pour autant que je sache il n'y a pas moyen de contourner cela, mais quelque chose comme:

// tmp and i are both iterators 
tmp = i; 
++i; 
hash_map.erase(tmp); 
+0

Selon la norme, il ++ et it-- (où il est un itérateur) équivaut à créer une température égale en décrémentant l'itérateur et en retournant la température. – hazzen

+0

Oui, mais le compilateur est libre d'appeler (i ++) avant ou après l'appel à effacer, donc si le compilateur décide de le faire (i ++) après l'effacement, alors i est invalide. – Rodyland

+0

Rodyland, avez-vous une référence pour cette réclamation? Je n'ai jamais entendu ça. – rlbond

2

Vous pouvez effacer encapsuler pour fournir la même interface pour tous les conteneurs que vous utilisez:

namespace detail { 
template<typename Container, typename R> 
struct SelectErase { 
    // by default, assume the next iterator is returned 
    template<typename Iterator> 
    Iterator erase(Container& c, Iterator where) { 
    return c.erase(where); 
    } 
}; 
// specialize on return type void 
template<typename Container> 
struct SelectErase<Container, void> { 
    template<typename Iterator> 
    Iterator erase(Container& c, Iterator where) { 
    Iterator next (where); 
    ++next; 
    c.erase(where); 
    return next; 
    } 
}; 

template<typename I, typename Container, typename R> 
SelectErase<Container,R> select_erase(R (Container::*)(I)) { 
    return SelectErase<Container,R>(); 
} 
} // namespace detail 

template<typename Container, typename Iterator> 
Iterator erase(Container& container, Iterator where) { 
    return detail::select_erase<Iterator>(&Container::erase).erase(container, where); 
} 

Cela nécessite soit:

  1. c.erase renvoie l'itérateur pour l'élément suivant. C'est ainsi que fonctionnent vector, deque et list. C.erase renvoie void et n'invalide pas l'itérateur suivant.
  2. C'est ainsi que map, set et hash_map (non-stdlib) fonctionnent.