从列表中删除 STL
STL deleting from list
我在使用 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,分配器>))的操作数无效" 我不太确定如何解决它。 谢谢,任何建议不胜感激!
您正在将Student
的实例与我假设没有定义operator==
重载函数的std::string
进行比较。您可以定义此运算符,也可以studentName
与存储学生姓名的成员字符串变量进行比较Student
。您可以考虑查看算法库中的std::remove_if
,您可以使用它来过滤掉任何没有该名称的学生。
您正在尝试将学生与字符串进行比较。默认情况下不会定义这样的比较,因此您必须自己定义一个正确的运算符,或者编写类似(*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;
}
}
- 您不推进迭代器。如果你碰巧擦除了第一个元素,你会崩溃,否则你会得到一个无限循环。然而。。。
- 有大量的例子如何正确迭代列表和擦除元素,例如:迭代 std::list 时擦除
删除迭代器指向的列表段时,迭代器不再有效。这就是为什么erase
将一个新的迭代器返回到被擦除的元素之后的元素。此外,您可能希望在循环中的某个点增加迭代器。试试这个:
while (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;
}
你的循环实际上等效于以下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
将不会更新,并且在循环的下一次迭代中,您将取消对不再存在的节点的迭代器的引用。这个问题的解决方案是知道erase
函数返回什么,即下一个节点的迭代器。这意味着一个可行的解决方案看起来像
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
}
}
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 删除包含包含动态对象的 STL 容器的智能指针
- 擦除是否删除 stl 无序列图元素使用的堆内存
- 在不使用任何 STL 容器的情况下删除重复项
- 在 c++ stl 映射中,删除具有重复值的条目
- 遍历 STL 映射(集/多集)的最佳方法,同时元素可能会在循环期间被删除并重新插入?
- 用于删除一系列值的 STL 容器
- 从字符串(STL)中删除所有重复字符
- 如何删除在没有STL的队列中存储在数组中的第一个字符串元素
- 如何从 STL 列表中删除结构记录
- C++ STL 中的 erase() 真的会删除元素吗?
- 根据不使用 STL C++中的值从哈希表中删除
- 仅通过迭代器删除 STL 容器元素
- 从列表中删除 STL
- 使用 C++11 迭代语法时从 STL 列表中删除
- 删除C++STL多映射中特定键的条目
- 有效删除C STL矢量中的双重条目
- 从 STL 容器继承并删除"新"运算符以防止由于缺少虚拟析构函数而导致未定义的行为是否有意义?
- 复制STL:删除元素、用户定义函数作为参数和事件队列
- c++ STL删除错误