2016-05-24 14 views
2

私はstd::list<some_object> eventsを持っています。最後のものを除くリストのすべての要素を削除したいと思います。だから私は(this threadにより示唆されるように)やって考える:それはエラーが発生してC++リストの最後まで消去するリスト(リスト内の1つの要素)

std::list<some_object>::iterator it = events.begin(); // Init iterator on top of list 
while(it!=*std::advance(events.end(),-1)) events.erase(it++); 

は、残念ながら、上記の作業をされていません。

error: invalid initialization of non-const reference of type ‘std::_List_iterator<node_info>&’ from an rvalue of type ‘std::__cxx11::list<node_info>::iterator {aka std::_List_iterator<node_info>}’ 
      while(it!=*std::advance(event_heap.end(),-1)){ 

しかし、list::endはイテレータを返すことになっていませんか?私は間違って何をしていますか?

+1

なぜ 'std :: list :: erase'を使わないのですか? – NathanOliver

+1

'events.erase(events.begin()、 - (events.end()))の何が問題なのですか? – Beta

+1

'std :: list :: erase()'を使うべきですが、代わりに 'back()'アイテムを '' std :: list''に '' push_back() 'してから、' 'std :: stap :: list temp :: swap() 'あなたのメイン' std :: list'との間の一時的な一時的な関係。 temp.push_back(events.back()); std :: swap(events、temp); 'tempが範囲外になると、保存しなかったアイテムはすべて解放されます。 –

答えて

1

But, isn't list::end supposed to return an iterator?

はい、しかしevent_heap.end()は一時変数であり、非const参照にバインドすることができない一方でstd::advanceは、その第一のパラメータとして非const参照を取ります。

std::advanceは何も返しません(つまり、void)、operator*を使用したり、itと比較することはできません。

直接固定になりますように:

std::list<some_object>::iterator it = events.begin(); 
auto one_before_end = events.end(); 
std::advance(one_before_end, -1); // or --one_before_end; 
while (it != one_before_end) events.erase(it++); 

ところで:std::list::eraseはイテレータの範囲を取るオーバーロードを持っているので、あなただけのことができます:

std::prevの一つの典型的な使用だ
events.erase(events.begin(), one_before_end); 
+1

をコピーするのではなく、オブジェクトを一時リストに移動することができます。ありがとうございます@songyuanyaoとすべてのあなたの啓発の応答! @NathanOliver @Beta:消去する前に、個々のリスト要素に対していくつかの追加操作を行う必要があることを忘れていました。したがって、リスト要素を1つずつ消去する必要があります。したがって、whileループはおそらくこれを行うための最も直接的な方法です。代わりに、 'std :: list :: remove_if'でファンクション述語を使うこともできます... – maurizio

6

remove最後の要素を除くすべての要素が必要な場合は、std::prev(基本的にはstd::advanceを使用しています)をエンドイテレータで使用するのが最も慣用的な方法です。

myList.erase(myList.begin(), std::prev(myList.end())); 

例:

#include <iostream> 
#include <iterator> 
#include <list> 

int main(){ 
    std::list<int> ls = {3, 5, 9, 2}; 

    if(!ls.empty()) 
     ls.erase(ls.begin(), std::prev(ls.end())); 

    for(auto x : ls) 
     std::cout << x << std::endl; 

    return 0; 
} 

プリント:

2 

レミールボー・コメントで指摘したように説明したように、非C++ 11コンパイラのために、あなただけのstd::advance()を使用することができますsongyuanyao's answer

+0

' std :: prev() 'はC++ 11で新しくなったことに注意してください。以前のバージョンでは、 'std :: advance()'を使い続ける必要がありました。 –

+0

@RemyLebeau、ありがとうございました。 :-) – WhiZTiM

+0

一般に 'prev(ls.end())'やそれに相当するものを実行する前に '!ls.empty()'をチェックするべきです –

関連する問題