2017-10-21 246 views
0

Im與STl有問題。我試圖遍歷STL列表中的學生對象。我試圖刪除對象,當我找到一個匹配的比較。但是,我在比較時收到錯誤。這是我迄今所做的:STL從列表中刪除

string studentName; 
       cout<<"Enter name of student to remove"; 
       cin>>studentName; 

       list<Student>::iterator it = studentList.begin(); 
       while (it != studentList.end()){ 
        if(*it== studentName){ 
         studentList.erase(it); 
        } 
       } 

我得到錯誤「無效操作數爲二進制表達式(‘VALUE_TYPE’(又名‘學生’)和‘字符串’(又名‘basic_string的,分配器>’)) 「 我不太清楚如何解決它。 謝謝,任何建議表示讚賞!

+1

你忘了的東西: 1.一個完整的代碼示例。 (例如,studentList從不定義) 2.編譯器的實際錯誤。 –

回答

2

您正試圖將學生與字符串進行比較。這種比較不是默認定義的,所以你必須自己定義一個合適的運算符或者寫一些類似(*it).getName() == studentName的地方,其中getName是Student的成員函數,它返回學生的名字。 另外,您的for循環不正確。它應該是這樣的:

for(auto it = studentList.begin(); it != studentList.end();) { 
    if((*it).getName() == studentName) { 
     it = studentList.erase(it); 
    } else { 
     ++it; 
    } 
} 

編輯:如果您決定再在這裏過載比較操作是如何做到這一點小費:

bool operator==(const Student& student, const std::string& name) { 
    return student.getName() == name; 
} 

bool operator==(const std::string& name, const Student& student) { 
    return student == name; 
} 

bool operator!=(const Student& student, const std::string& name) { 
    return !(student == name); 
} 

bool operator!=(const std::string& name, const Student& student) { 
    return !(student == name); 
} 

對於這個問題的第一個目的以上四種重載就足夠了,但通常定義幾個版本以避免將來出現意外情況會更好。另外,如果Student類沒有任何成員函數,比如getName(除非Student是一個簡單的結構,所有數據成員都是公開的,否則強烈建議使用此類函數),那麼必須更改第一個重載(其餘部分參考到第一個所以他們會自動調整到改變)是這樣的:

bool operator==(const Student& student, const std::string& name) { 
    return student.name == name; 
} 

此外,如果學生的名字是私人或受保護的,也沒有辦法從公共情境訪問它,那麼你也必須在您的學生定義中添加朋友聲明:

class Student { 
public: 

// Public interface... 

private: 
    std::string name; 

    friend bool operator==(const Student& student, const std::string& name); 
}; 

朋友聲明的位置不符合只要它在類的定義內。再一次,你只需要讓第一個重載特權,因爲其餘的只是調用第一個特權。
現在可以更改循環:

for(auto it = studentList.begin(); it != studentList.end();) { 
    if(*it == studentName) { 
     it = studentList.erase(it); 
    } else { 
     ++it; 
    } 
} 
+0

您的解決方案完美運行時拋出一個錯誤!爲了學習的目的,你可以給我一些建議,關於如何重載==運算符,因爲我使用迭代器 – coder666

+0

無論你是否使用迭代器都沒關係。我編輯了答案,向您展示如何重載操作員。 – navyblue

1

當您刪除迭代器指向的列表段時,迭代器不再有效。這就是爲什麼erase爲刪除之後的元素返回一個新的迭代器。另外,您可能想在循環中的某個點增加迭代器。試試這個:

while (it != studentList.end()){ 
    if(*it == studentName) 
     it = studentList.erase(it); 
    else 
     ++it; 
} 

編輯:現在你已經張貼的錯誤,很明顯,你有另外一個問題。查看每個人如何解決這個問題的答案。

1

你的循環實際上等同於以下for循環:

for (list<Student>::iterator it = studentList.begin(); 
    it != studentList.end(); 
    /* EMPTY */) 
{ 
    if(*it== studentName){ 
     studentList.erase(it); 
    } 
} 

通知的for循環半句怎麼是空的?這意味着你永遠不會增加或修改for語句中的變量it,並且也不會循環體!這意味着it將永遠不會改變,並且您有一個無限循環。

解決此問題的簡單而明顯的方法是在循環中增加it。回到你原來的循環,與修訂補充說:

list<Student>::iterator it = studentList.begin(); 
while (it != studentList.end()){ 
    if(*it== studentName){ 
     studentList.erase(it); 
    } 

    ++it; // Make iterator "point" to the next node 
} 

然而此修復程序以另一種方式存在缺陷。這是因爲當你刪除一個節點時,你會在你刪除的節點之後跳過節點,所以你會錯過一個節點。天真的解決方案是隻增加it如果不刪除節點:

while (it != studentList.end()){ 
    if(*it== studentName){ 
     studentList.erase(it); 
    } else { 
     ++it; // Make iterator "point" to the next node 
    } 
} 

該解決方案是有缺陷的,你將有未定義的行爲如果你刪除一個節點。這是因爲it不會被更新,並且循環的下一次迭代將取消引用迭代器到不再存在的節點。 這個問題的解決方法是知道什麼the erase function returns,即迭代器到下面的節點。這意味着工作的解決方案看起來像

while (it != studentList.end()){ 
    if(*it== studentName){ 
     it = studentList.erase(it); // Make iterator "point" to node after removed node 
    } else { 
     ++it; // Make iterator "point" to the next node 
    } 
} 
+0

最後一個for循環是錯誤的。如果循環找到一個等於'studentName'的對象,那麼它將跳過下一個元素 - 它根本不會檢查它。所以我會堅持最後一個解決方案。 – navyblue

+0

@navyblue我知道它有什麼問題,但累得弄清楚。謝謝你提醒我。 –

1
  1. 不提前迭代器。如果你碰巧抹掉了第一個元素,你會崩潰,否則你將會得到一個無限循環。然而,...
  2. 有大量的例子如何正確迭代列表和擦除元素,例如,在這裏:Erasing while iterating an std::list
+0

我修復了循環,但是在if(* it == studentName) – coder666

4

您正在與std::string這我假設沒有一個定義operator==重載函數比較Student一個實例。您可以定義此運算符或將studentName與存儲學生姓名的Student中的成員字符串變量進行比較。您可以考慮在算法庫中查找std::remove_if,您可以使用該算法庫過濾掉任何沒有該名稱的學生。

1

您試圖比較字符串和學生。另外,你並沒有推進迭代器,因此該循環將無法停止。嘗試沿着這些方向:

while (it != studentList.end()) { 
    if(it->getName == studentName) { 
     it = studentList.erase(it); 
    } 
    ++it; 
}