web-dev-qa-db-ja.com

逆イテレーターで消去を呼び出す方法

私はこのようなことをしようとしています:

for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
    if ( *i == pCursor )
    {
        m_CursorStack.erase( i );
        break;
    }
}

ただし、消去には逆反復子ではなく反復子が必要です。逆反復子を通常の反復子に変換する方法や、この要素をリストから削除する別の方法はありますか?

153
0xC0DEFACE

さらに調査とテストを行った結果、解決策が見つかりました。どうやら標準[24.4.1/1]によれば、i.base()とiの関係は次のとおりです。

&*(reverse_iterator(i)) == &*(i - 1)

(から ドブス博士の記事 ):

alt text

そのため、base()を取得するときにオフセットを適用する必要があります。したがって、解決策は次のとおりです。

m_CursorStack.erase( --(i.base()) );

[〜#〜] edit [〜#〜]

C++ 11用の更新。

reverse_iterator iは変更されていません:

m_CursorStack.erase( std::next(i).base() );

reverse_iterator iは高度です:

std::advance(i, 1);
m_CursorStack.erase( i.base() );

これは以前のソリューションよりもはるかに明確です。必要なものを使用してください。

156
0xC0DEFACE

m_CursorStack.erase( (++i).base())はiの値を変更するため、forループ(元の質問を参照)で使用すると問題になる可能性があることに注意してください。正しい式はm_CursorStack.erase((i+1).base())です

14
Andrey

...またはリストからこの要素を削除する別の方法?

これには-std=c++11フラグが必要です(autoの場合):

auto it=vt.end();
while (it>vt.begin())
{
    it--;
    if (*it == pCursor) //{ delete *it;
        it = vt.erase(it); //}
}
11
slashmais

ここで_reverse_iterator_のbase()メソッドを使用して結果をデクリメントすると、_reverse_iterator_ sには通常のiteratorsと同じステータスが与えられないことに注意する価値があります。通常、このような理由から、通常のiteratorsを_reverse_iterator_ s(および_const_iterator_ sおよび_const_reverse_iterator_ s)よりも優先する必要があります。理由の詳細な議論については Doctor Dobbs 'Journal をご覧ください。

3
Adam Rosenfield
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--;
}
3
Nismo

進行中にすべてを消去する必要がない場合は、問題を解決するために、erase-removeイディオムを使用できます。

_m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());
_

_std::remove_は、pCursorに一致するコンテナ内のすべてのアイテムを最後に交換し、最初の一致するアイテムに反復子を返します。次に、範囲を使用するeraseは、最初の一致から消去され、最後に移動します。一致しない要素の順序は保持されます。

_std::vector_を使用している場合は、コンテンツの途中での消去に大量のコピーや移動が必要になる可能性があるため、これはより速く動作する可能性があります。

または、上記のreverse_iterator::base()の使用を説明する答えは興味深いものであり、知る価値があります。述べられている正確な問題を解決するには、_std::remove_の方が適していると思います。

2
gavinbeatty

面白いことに、このページにはまだ正しい解決策がありません。したがって、以下は正しいものです。

前方反復子の場合、解決策は簡単です。

std::list< int >::iterator i = myList.begin();
while ( ; i != myList.end(); ) {
  if ( *i == to_delete ) {
    i = myList.erase( i );
  } else {
    ++i;
  } 
}

逆反復子の場合、同じことをする必要があります。

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;
  } 
}

ノート:

  • イテレータからreverse_iteratorを構築できます
  • std::list::eraseの戻り値を使用できます
2
Gaetano Mendola

そして、以下は、消去の結果を逆イテレータに変換して、コンテナ内の要素を消去し、逆に繰り返し処理するためのコードです。少し奇妙ですが、最初または最後の要素を消去する場合でも動作します:

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;
}
2
etham

他の答えを補完するために、私はこの質問につまずいたので、あまり成功せずにstd :: stringについて検索したので、std :: string、std :: string :: eraseおよびstd :: reverse_iteratorを使用して応答します

私の問題は、完全なファイル名文字列から画像ファイル名を消去することでした。それはもともとstd :: string :: find_last_ofで解決されましたが、私は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\'

これは、アルゴリズム、イテレータ、および文字列ヘッダーを使用します。

0
fmmarques

何かを明確にしたかっただけです。上記のコメントと回答のいくつかでは、消去用のポータブルバージョンは(++ i).base()として言及されています。ただし、何か不足している場合を除き、正しいステートメントは(++ ri).base()です。つまり、reverse_iterator(イテレーターではなく)を「インクリメント」します。

昨日、似たようなことをする必要が生じたので、この投稿は役に立ちました。みんな、ありがとう。

0
user1493570