Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从列表中删除STL_C++_Stl_Iterator - Fatal编程技术网

C++ 从列表中删除STL

C++ 从列表中删除STL,c++,stl,iterator,C++,Stl,Iterator,我在STl方面有问题。我正在尝试遍历学生对象的STL列表。当我找到匹配的比较时,我试图删除对象。但是,在进行比较时,我收到一个错误。这就是我到目前为止所做的: string studentName; cout<<"Enter name of student to remove"; cin>>studentName; list<Student>::iterator

我在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);
                    }
                }
字符串studentName;
coutstudentName;
list::iterator it=studentList.begin();
while(it!=studentList.end()){
如果(*it==studentName){
学生名单。删除(它);
}
}
我得到错误“二进制表达式('value_type'(aka'Student')和'string'(aka'basic_string,allocator>')的操作数无效” 我不太清楚如何解决它。
谢谢,任何建议都将不胜感激

删除迭代器指向的列表段时,迭代器不再有效。这就是为什么
erase
将一个新的迭代器返回到被擦除的元素后面的元素。此外,您可能希望在循环中的某个点增加迭代器。试试这个:

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

编辑:现在您已经发布了错误,很明显您还有另一个问题。查看每个人关于如何修复此问题的答案。

您的循环实际上相当于以下
for
循环:

for (list<Student>::iterator it = studentList.begin();
     it != studentList.end();
     /* EMPTY */)
{
    if(*it== studentName){
        studentList.erase(it);
    }
}
但是此修复程序在另一方面存在缺陷。这是因为删除节点时,会在删除节点后跳过该节点,因此会错过一个节点。简单的解决方案是,如果不删除节点,则只增加
it

while (it != studentList.end()){
    if(*it== studentName){
        studentList.erase(it);
    } else {
        ++it;  // Make iterator "point" to the next node
    }
}
此解决方案的缺陷在于,如果删除节点,将具有未定义的行为。这是因为
it
不会被更新,在循环的下一次迭代中,您将取消对不再存在的节点的迭代器的引用。这个问题的解决方案是知道什么,即对以下节点的迭代器。这意味着一个有效的解决方案看起来像

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
    }
}
  • 您不需要推进迭代器。如果您碰巧删除了第一个元素,您将崩溃,否则将得到一个无限循环。然而
  • 关于如何正确迭代列表和删除元素,有很多示例,例如:

  • 您正在将
    Student
    的实例与
    std::string
    进行比较,我假设该字符串没有定义的
    运算符==
    重载函数。您可以定义此运算符,也可以将
    studentName
    与存储学生姓名的
    Student
    中的成员字符串变量进行比较。您可以考虑在代码库中查看<代码> STD::ReaveVII:< /C> >,您可以使用它来过滤任何没有该名称的学生。

    < P>您试图将学生与String进行比较。默认情况下未定义此类比较,因此您必须自己定义适当的运算符,或者编写类似于
    (*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.name == name;
    }
    
    编辑:如果您决定重载比较运算符,则以下是有关如何操作的提示:

    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是一个所有数据成员都是公共的简单结构),那么您必须更改第一个重载(其余的重载引用第一个重载,以便自动调整以适应更改),如下所示:

    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.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;
        }
    }
    

    您正在尝试比较字符串和学生。此外,您没有推进迭代器,因此循环将无法停止。试着做以下几点:

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

    你忘记的事情:1。一个完整的代码示例。(例如,从未定义过studentList)2。编译器的实际错误。我修复了循环,但是如果(*it==studentName)您的解决方案工作正常,它会抛出一个错误!出于学习的目的,你能不能给我一些建议,告诉我如何重载==运算符,因为我使用的是迭代器。不管你是否使用迭代器。我编辑了答案,向您展示了如何重载运算符。最后一个for循环是错误的。如果循环找到一个等于
    studentName
    的对象,那么它将跳过下一个元素-它根本不会检查它。所以我会坚持最后一个解决方案。@navyblue我知道它出了问题,但很难找出答案。谢谢你提醒我。