2017-10-21 197 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; 
}