J'essaye de faire quelque chose comme ça:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Cependant, l'effacement prend un itérateur et non un itérateur inverse. existe-t-il un moyen de convertir un itérateur inverse en itérateur régulier ou un autre moyen de supprimer cet élément de la liste?
i != m_CursorStack.rend()
. Au lieu de cela, écrivezi = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;
. Autrement dit, initialisez un itérateur que vous pouvez conserver pour des comparaisons répétées - en supposant que la position finale ne changera pas en tant qu'effet secondaire de votre corps de boucle.std::remove
?Réponses:
Après quelques recherches et tests supplémentaires, j'ai trouvé la solution. Apparemment, selon la norme [24.4.1 / 1], la relation entre i.base () et i est:
&*(reverse_iterator(i)) == &*(i - 1)
(extrait d'un article du Dr Dobbs ):
Vous devez donc appliquer un décalage lors de l'obtention de la base (). Par conséquent, la solution est:
ÉDITER
Mise à jour pour C ++ 11.
reverse_iterator
i
est inchangé:m_CursorStack.erase( std::next(i).base() );
reverse_iterator
i
est avancé:std::advance(i, 1); m_CursorStack.erase( i.base() );
Je trouve cela beaucoup plus clair que ma solution précédente. Utilisez celui dont vous avez besoin.
la source
m_CursorStack.erase( (++i).base())
(mec, faire ce truc avec des itérateurs inversés me fait mal à la tête ...). Il convient également de noter que l'article DDJ est incorporé dans le livre "Effective STL" de Meyer.*
utilisiez, mais nous parlons de l'élément que vous pointeriez si vous lesbase
utilisiez, qui est un élément à droite. Je ne suis pas fan des solutions--(i.base())
ou(++i).base()
car elles font muter l'itérateur. Je préfère(i+1).base()
ce qui fonctionne aussi.Veuillez noter que cela
m_CursorStack.erase( (++i).base())
peut poser un problème s'il est utilisé dans unefor
boucle (voir la question d'origine) car cela change la valeur de i. L'expression correcte estm_CursorStack.erase((i+1).base())
la source
iterator j = i ; ++j
, cari+1
ne fonctionne pas sur un itérateur, mais c'est la bonne idéem_CursorStack.erase(boost::next(i).base())
avec Boost. ou en C ++ 11m_CursorStack.erase(std::next(i).base())
Cela nécessite le
-std=c++11
drapeau (pourauto
):auto it=vt.end(); while (it>vt.begin()) { it--; if (*it == pCursor) //{ delete *it; it = vt.erase(it); //} }
la source
C'est drôle qu'il n'y ait pas encore de solution correcte sur cette page. Donc, ce qui suit est le bon:
Dans le cas de l'itérateur avant, la solution est simple:
std::list< int >::iterator i = myList.begin(); while ( ; i != myList.end(); ) { if ( *i == to_delete ) { i = myList.erase( i ); } else { ++i; } }
En cas d'itérateur inversé, vous devez faire de même:
std::list< int >::reverse_iterator i = myList.rbegin(); while ( ; i != myList.rend(); ) { if ( *i == to_delete ) { i = decltype(i)(myList.erase( std::next(i).base() )); } else { ++i; } }
Remarques:
reverse_iterator
partir d'un itérateurstd::list::erase
la source
Bien que l'utilisation de la méthode
reverse_iterator
sbase()
et la décrémentation du résultat fonctionnent ici, il convient de noter que lesreverse_iterator
s n'ont pas le même statut que lesiterator
s réguliers . En général, vous devriez préférer lesiterator
s réguliers àreverse_iterator
s (ainsi qu'auxconst_iterator
s etconst_reverse_iterator
s), pour des raisons précises comme celle-ci. Voir le Journal du Docteur Dobbs pour une discussion approfondie sur les raisons.la source
typedef std::map<size_t, some_class*> TMap; TMap Map; ....... for( TMap::const_reverse_iterator It = Map.rbegin(), end = Map.rend(); It != end; It++ ) { TMap::const_iterator Obsolete = It.base(); // conversion into const_iterator It++; Map.erase( Obsolete ); It--; }
la source
Et voici le morceau de code pour reconvertir le résultat de l'effacement en un itérateur inverse afin d'effacer un élément dans un conteneur tout en itérant à l'inverse. Un peu étrange, mais cela fonctionne même en effaçant le premier ou le dernier élément:
std::set<int> set{1,2,3,4,5}; for (auto itr = set.rbegin(); itr != set.rend(); ) { if (*itr == 3) { auto it = set.erase(--itr.base()); itr = std::reverse_iterator(it); } else ++itr; }
la source
Si vous n'avez pas besoin de tout effacer au fur et à mesure, pour résoudre le problème, vous pouvez utiliser l'idiome effacer-supprimer:
m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());
std::remove
échange tous les éléments du conteneur qui correspondentpCursor
à la fin et renvoie un itérateur vers le premier élément correspondant. Ensuite, l'erase
utilisation d'une plage effacera de la première correspondance et ira jusqu'à la fin. L'ordre des éléments non correspondants est conservé.Cela pourrait fonctionner plus rapidement pour vous si vous utilisez un
std::vector
, où l'effacement au milieu du contenu peut impliquer beaucoup de copie ou de déplacement.Ou bien sûr, les réponses ci-dessus expliquant l'utilisation de
reverse_iterator::base()
sont intéressantes et valent la peine d'être connues, pour résoudre le problème exact posé, je dirais questd::remove
c'est un meilleur ajustement.la source
Je voulais juste clarifier quelque chose: dans certains des commentaires et réponses ci-dessus, la version portable pour l'effacement est mentionnée comme (++ i) .base (). Cependant, à moins que je ne manque quelque chose, la déclaration correcte est (++ ri) .base (), ce qui signifie que vous «incrémentez» le reverse_iterator (pas l'itérateur).
J'ai eu besoin de faire quelque chose de similaire hier et cet article m'a été utile. Merci tout le monde.
la source
Pour compléter les réponses des autres et parce que je suis tombé sur cette question en cherchant sur std :: string sans grand succès, voici une réponse avec l'utilisation de std :: string, std :: string :: erase et std :: reverse_iterator
Mon problème effaçait le nom de fichier d'une image d'une chaîne de nom de fichier complète. Il a été résolu à l'origine avec std :: string :: find_last_of, mais je recherche une autre manière avec std :: reverse_iterator.
std::string haystack("\\\\UNC\\complete\\file\\path.exe"); auto&& it = std::find_if( std::rbegin(haystack), std::rend(haystack), []( char ch){ return ch == '\\'; } ); auto&& it2 = std::string::iterator( std::begin( haystack ) + std::distance(it, std::rend(haystack)) ); haystack.erase(it2, std::end(haystack)); std::cout << haystack; ////// prints: '\\UNC\complete\file\'
Cela utilise des en-têtes d'algorithme, d'itérateur et de chaîne.
la source
L'itérateur inversé est assez difficile à utiliser. Donc, juste utilisé itérateur général. 'r' Il commence à partir du dernier élément. Quand trouver quelque chose à effacer. effacez-le et retournez l'itérateur suivant. Par exemple, lors de la suppression du 3e élément, il pointera le 4e élément actuel. et nouveau 3e. Il devrait donc être diminué de 1 pour se déplacer à gauche
void remchar(string& s,char c) { auto r = s.end() - 1; while (r >= s.begin() && *r == c) { r = s.erase(r); r -= 1; } }
la source