2009-06-19 19 views
14

Listeden geçen ve tüm çift sayıları silebilen bir liste yineleyici var. Numaraları düzgün yazdırmak için liste yineleyicisini kullanabilirim ancak listenin remove() işlevini kullanamıyorum ve dereferanslı yineleyiciyi iletemiyorum.List Iterator Kaldır()

Kaldır() ifadesi etkin olduğunda, * itr bozuk olur? Birisi bunu açıklayabilir mi?

#include <iostream> 
#include <list> 

#define MAX 100 

using namespace std; 

int main() 
{ 
    list<int> listA; 
    list<int>::iterator itr; 

    //create list of 0 to 100 
    for(int i=0; i<=MAX; i++) 
     listA.push_back(i); 

    //remove even numbers 
    for(itr = listA.begin(); itr != listA.end(); ++itr) 
    { 
     if (*itr % 2 == 0) 
     { 
      cout << *itr << endl; 
      listA.remove(*itr); //comment this line out and it will print properly 
     } 
    } 
} 

cevap

41

Yukarıdaki kodunuzda birkaç sorun var. Öncelikle, remove kaldırılan öğelere işaret eden yineleyicileri geçersiz kılar. Daha sonra tekrarlayıcıyı kullanmaya devam etmek için devam edersiniz. remove nolu öğenin (unsurların) genel durumda (hangisi olmasa da) silineceğini söylemek zordur, çünkü birden fazlayı kaldırabilir.

İkinci olarak, muhtemelen yanlış yöntemi kullanıyorsunuzdur. Kaldır herhangi bir eşleme öğesi arayan listedeki tüm öğeler arasında yineleyecek - bu sizin durumunuzda verimsiz olacaktır çünkü tek bir tane var. erase yöntemini kullanmanız gerektiği gibi görünüyor, muhtemelen yalnızca öğeyi yineleyicinin konumuna silmek istersiniz. erase hakkında iyi bir şey, bir sonraki geçerli konumda olan bir yineleyici döndürür. yapıyorsun olarak

//remove even numbers 
for(itr = listA.begin(); itr != listA.end();) 
{ 
    if (*itr % 2 == 0) 
    { 
     cout << *itr << endl; 
     itr=listA.erase(itr); 
    } 
    else 
     ++itr; 
} 

Son olarak, aynı şeyi remove_if kullanabilirsiniz:

bool even(int i) { return i % 2 == 0; } 

listA.remove_if(even); 
2

Başvurulan öğeyi sildikten sonra yineleyici kullanamazsınız. Ancak, remove()'dan sonra silinmemiş öğelere başvuran liste yineleyicileri geçerli kalmalıdır.

-1

Yineleyiciler, kalan yapının uzunluğuna bağlı olduklarından, yineleyicilerin çoğu, yineleyici kullanımdayken listenin değiştirilmesine izin vermez. Listeden geçmek ve değiştirmek isterseniz, yineleyiciden bağımsız bir döngü kullanmak zorunda kalacaksınız.

+4

STL yineleyicilerinin yapının uzunluğu üzerinde herhangi bir bağımlılığı olmadığını belirtmeliyim. Yineleyiciler genellikle belirli öğeleri silmenize izin verir, örneğin vektör yineleyicileri yineleyiciden geçen öğeleri silmenize izin verir ve liste yineleyicileri yineleyici tarafından işaret edilmeyen herhangi bir öğeyi silmenize izin verir –

0

böyle bir şey kullanmak Could: kullanmak için deyimsel yolu böyle bir şeydir

int main(){ 

list<int>*a=new list<int>; 
a->push_back(1); 
a->push_back(2); 
a->push_back(3); 

list<int>::iterator I; 

I=a->begin(); ++I; 

a->erase(I++); 
cout<<*I<<endl; 
} 
:
container.erase(it++); 

Bu örnekte üzerinde çalıştı

ve istediğim gibi 3 görüntülendi. Şimdi bunun geçerli olup olmadığını veya "bazen iş ve bazen de" olmayanlardan birini bilmiyorum.

DÜZENLEME: Belki de derleyici nedeniyle. Örneğin, kullandığım derleyici (GNU gcc-g ++) listeleri (std: :) döngüsel olarak, yani listeden sonra yineleyici artırırsam -> end() baştan başlamanıza neden oluyor.

+0

Bu, std :: list 'yineleyicileri için çalışır çünkü Bu yineleyiciler yalnızca işaret ettikleri öğe silindiğinde geçersiz kılınır. Ancak bu, std :: vector' yineleyicileri için çalışmayacaktır çünkü işaret ettikleri öğe veya işaret ettikleri öğeden önce herhangi bir öğe silindiğinde bu yineleyiciler geçersiz olur. – David