C ++ - begin () возвращает итератор end () с непустым списком - PullRequest
1 голос
/ 01 апреля 2020

Как показывает вопрос, у меня очень странное поведение с итераторами и списками. Итак, проблема (класса) запрашивает функцию, которая удаляет все элементы, которые удовлетворяют условию из списка, и, когда я попытался охватить случай, когда у меня есть список, где все элементы одинаковы, я обнаружил, что последний элемент сохранился .

Вот код:

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();
        }
    }
}

Я использовал itend просто чтобы увидеть значение при отладке. Вот сеанс: See that the list *t* is not empty but t.begin() returns the same as t.end()

Как это возможно? П.Д .: Я не ищу других подходов к проблеме.

Ответы [ 2 ]

6 голосов
/ 01 апреля 2020

Это потому, что вы делаете it++ (пост-действие l oop) после вашего it = t.begin().

Удалите это и вставьте else it++ (хотя я предпочитаю ++it ) в твоем теле; это должно произойти только тогда, когда вы не делаете стирание.

Это похоже на метод для стирания из map во время итерации по нему .

Подчеркнув этот метод, мы можем заметить, что ваш else it = t.begin() расточителен: вы каждый раз начинаете с начала l oop, что увеличивает сложность алгоритма c вашего алгоритм.

Вместо этого используйте итератор, возвращаемый 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;
        }
    }
}

Обратите внимание, что нам больше не нужно проверять список на пустоту; если он теперь пуст, it будет t.end(), а l oop все равно закончится.


В настоящее время вы не используете itend. Вы не можете просто поменять его в условие l oop по понятным причинам, но если вы сбросите его, когда он будет признан недействительным, это может быть целесообразным:

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

Однако, это может быть понятнее просто придерживайтесь своего исходного кода, но удалите неиспользованную itend декларацию.

3 голосов
/ 01 апреля 2020

Используемый подход в функции

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();
        }
    }
}

недопустим. Итератор становится недействительным после вызова метода erase.

Вы можете написать такую ​​функцию, как

void esborra_tots(list<Estudiant>& t, int x) {
    for ( auto it = t.begin(); it != t.end(); ) {
        if ((*it).consultar_DNI() == x) {

            it = t.erase(it);
        }
        else {
            ++it;
        } 
    }
}

Но это слишком сложно. Функция будет выглядеть намного проще, если использовать метод remove_if.

Например,

void esborra_tots(list<Estudiant>& t, int x) {
    t.remove_if( [&x]( const auto &item ) { return item.consultar_DNI() == x; } );
}

Вот демонстрационная программа.

#include <iostream>
#include <list>

int main() 
{
    std::list<int> list = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for ( const auto &item : list ) std::cout << item << ' ';
    std::cout << '\n';

    list.remove_if( []( const auto &item ){ return item % 2 == 0; } );

    for ( const auto &item : list ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;
}

Ее вывод

0 1 2 3 4 5 6 7 8 9 
1 3 5 7 9 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...