我在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);
}
}
我收到错误&#34;二进制表达式的操作数无效(&#39; value_type&#39;(又名&#39;学生&#39;)和&#39;字符串&#39;(又名&#39; ; basic_string,allocator&gt;&#39;))&#34; 我不太确定如何解决它。 谢谢,任何建议表示赞赏!
答案 0 :(得分:4)
您正在将Student
的实例与std::string
进行比较,我假设它没有定义operator==
重载函数。您可以定义此运算符,也可以将studentName
与Student
中存储学生姓名的成员字符串变量进行比较。你可以考虑在算法库中查看std::remove_if
,你可以用来过滤掉那些没有这个名字的学生。
答案 1 :(得分:2)
您正在尝试将Student与字符串进行比较。默认情况下不会定义这样的比较,因此您必须自己定义适当的运算符或编写类似(*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;
}
}
答案 2 :(得分:1)
当您删除迭代器指向的列表段时,迭代器不再有效。这就是为什么erase
将一个新的迭代器返回到被删除的元素之后的原因。此外,您可能希望在循环中的某个点增加迭代器。试试这个:
while (it != studentList.end()){
if(*it == studentName)
it = studentList.erase(it);
else
++it;
}
修改:现在您已发布错误,很明显您还有其他问题。看看每个人如何解决这个问题的答案。
答案 3 :(得分:1)
您的循环实际上等同于以下for
循环:
for (list<Student>::iterator it = studentList.begin();
it != studentList.end();
/* EMPTY */)
{
if(*it== studentName){
studentList.erase(it);
}
}
注意for
循环的最后一部分是如何为空的?这意味着你永远不会增加或修改it
语句中的变量for
,也不会修改循环体!这意味着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
}
}
答案 4 :(得分:1)
答案 5 :(得分:1)
您正在尝试比较字符串和学生。此外,您没有推进迭代器,因此该循环将无法停止。尝试以下几点:
while (it != studentList.end()) {
if(it->getName == studentName) {
it = studentList.erase(it);
}
++it;
}