C++ - begin() 返回带有非空列表的 end() 迭代器

Pau*_*opa 1 c++ c++11 visual-studio-code

正如问题所暗示的那样,我对迭代器和列表有一种非常奇怪的行为。因此,(类)问题需要一个函数来擦除列表中满足条件的所有元素,并且当我试图涵盖我有一个所有元素都相同的列表的情况时,我发现最后一个元素仍然存在.

这是代码:

void esborra_tots(list<Estudiant>& t, int x) {
    list<Estudiant>::iterator it;
    list<Estudiant>::iterator itend = t.end();

    for (it = t.begin(); it != t.end(); it++) {
        if ((*it).consultar_DNI() == x) {

            t.erase(it);
            if (t.empty()) return;
            else it = t.begin();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用itend只是为了在调试时查看值。这是会议: 看到列表 *t* 不为空,但 t.begin() 返回与 t.end() 相同

这怎么可能?PD:我不是在寻找解决这个问题的其他方法。

Ast*_*ngs 6

这是因为你在做it++你的后(循环后的动作)it = t.begin()

删除它,并在您的循环体中粘贴一个else it++(尽管我更喜欢++it);它只需要在您进行擦除时发生。

这类似于迭代它mapwhile擦除方法。

从该方法中获得提示,我们可以注意到您else it = t.begin()是浪费的:您每次都从循环的开头开始,这增加了算法的算法复杂性。

相反,使用由 返回的迭代器erase

void esborra_tots(list<Estudiant>& t, int x) {
    list<Estudiant>::iterator it;
    list<Estudiant>::iterator itend = t.end();

    for (it = t.begin(); it != t.end(); ) {
        if ((*it).consultar_DNI() == x) {
            it = t.erase(it);
        }
        else {
            ++it;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意我们如何不再需要检查列表是否为空;如果它现在是空的,it将会是t.end()并且循环无论如何都会结束。


目前,您没有使用itend. 出于显而易见的原因,您不能仅仅将它交换到循环条件中,但是如果您在它失效时重置它,那么它可能是值得的:

void esborra_tots(list<Estudiant>& t, int x) {
    for (auto it = t.begin(), end = t.end(); it != end; ) {
        if (it->consultar_DNI() == x) {
            it = t.erase(it);
            end = t.end();
        }
        else {
            ++it;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,坚持使用原始代码但删除未使用的itend声明可能会更清楚。