WindowsとMacの間でクロスプラットフォームコードを書いています。
List :: end()が「リストの最後の要素に続く位置をアドレス指定するイテレータを返し」、リストを順方向にトラバースするときにチェックできる場合、逆方向にトラバースする最良の方法は何ですか?
このコードはMacでは機能しますが、Windowsでは機能しません(最初の要素を超えてデクリメントすることはできません)。
list<DVFGfxObj*>::iterator iter = m_Objs.end();
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ?
{
}
これはWindowsで機能します。
list<DVFGfxObj*>::iterator iter = m_Objs.end();
do{
iter--;
} while (*iter != *m_Objs.begin());
Forループで実装できる別の逆方向トラバース方法はありますか?
イテレータの代わりにreverse_iteratorを使用します。 begin()&end()の代わりにrbegin()&rend()を使用してください。
BOOST_FOREACH マクロを使用する場合の別の可能性は、Boost 1.36.0で導入されたBOOST_REVERSE_FOREACHマクロを使用することです。
リストを逆反復する最良/最も簡単な方法は、(すでに述べたように)逆反復子rbegin/rendを使用することです。
しかし、「現在の」イテレータの位置を1つずらせて格納する逆イテレータが実装されていることを述べておきました(少なくともGNU標準ライブラリの実装))。
これは、インプリメンテーションを単純化するために行われます。これは、逆の範囲が前の範囲[begin、end)および[rbegin、rend)と同じセマンティクスを持つためです。
これが意味することは、イテレータを逆参照することは、新しい一時ファイルを作成し、次にそれをデクリメントすることを含むということです毎回:
reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
したがって、reverse_iteratorの逆参照は通常の反復子よりも遅くなります。
ただし、代わりに通常の双方向イテレータを使用して、自分で逆反復をシミュレートし、このオーバーヘッドを回避できます。
for ( iterator current = end() ; current != begin() ; /* Do nothing */ )
{
--current; // Unfortunately, you now need this here
/* Do work */
cout << *current << endl;
}
テストでは、このソリューションがループの本体で使用される約5倍高速であることを示しました各逆参照に対してが使用されました。
注:std :: coutがボトルネックになる可能性があるため、テストは上記のコードでは行われませんでした。
また、注:「ウォールクロック時間」の差は約5秒で、標準サイズ::リストのサイズは1000万要素です。したがって、現実的には、データのサイズがそれほど大きくない限り、rbegin()rend()に固執するだけです!
おそらくリバースイテレータが必要です。メモリから:
list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for( ; iter != m_Objs.rend(); ++iter)
{
}
Ferruccioがすでに述べたように、reverse_iteratorを使用します。
for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i)
これはうまくいくはずです:
list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for (; iter!= m_Objs.rend(); iter++)
{
}