Почему этот векторный итератор не увеличивается? - PullRequest
19 голосов
/ 23 сентября 2010

Я пытаюсь удалить содержимое вектора и получаю сообщение об ошибке - векторный итератор не может быть увеличен.

Это мой деструктор:

City::~City()
{
    vector <Base*>::iterator deleteIterator;
    for (deleteIterator = m_basesVector.begin() ; deleteIterator != m_basesVector.end() ; deleteIterator++)
        m_basesVector.erase(deleteIterator);
}  

спасибо.

Ответы [ 8 ]

44 голосов
/ 23 сентября 2010

erase делает недействительным итератор.Вы не можете использовать это больше.К счастью для вас, он возвращает итератор, который вы можете использовать:

vector <Base*>::iterator deleteIterator = m_basesVector.begin();
while (deleteIterator != m_basesVector.end()) {
    deleteIterator = m_basesVector.erase(deleteIterator);
}

Или:

m_basesVector.clear();

Вы несете ответственность за освобождение памяти, на которую указывают указатели в векторе?Если по этой причине вы выполняете итерацию (и ваша настоящая программа имеет больше кода, который вы не показали, который освобождает эти объекты в цикле), то имейте в виду, что удаление из начала вектора - медленная операция,потому что на каждом шаге все элементы вектора должны быть смещены вниз на одно место.Лучше было бы зациклить вектор, освобождая все (тогда clear() вектор, хотя, как говорит Майк, в этом нет необходимости, если вектор является членом разрушаемого объекта).

11 голосов
/ 23 сентября 2010

Проблема в том, что вы пытаетесь использовать итератор при использовании функции erase (). erase (), push_back (), insert () и другие модифицирующие функции делают недействительными итераторы в STL.

Просто используйте функцию clear ():

City::~City()
{
    m_basesVector.clear();
}  
3 голосов
/ 23 сентября 2010

Если вы пытаетесь освободить данные в векторе, сделайте это:

for (std::vector<Base*>::iterator it = v.begin(), e = b.end(); it != e; ++it) 
    delete *it;
2 голосов
/ 26 июля 2017

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

Я недавно столкнулся с этим сообщением об ошибке ивсе строки кода проверены (не было «стирания» или чего-либо подобного; вектор был просто прочитан).

В конце концов, я понял, что есть проблема с вложенными циклами.

ДляНапример, рассмотрим что-то вроде этого:

`for (it=begin(); it!=end();i++)
{
    for (; it!=end();i++)
    {
    }
}`

Когда вы закончите с вложенным циклом, он будет увеличивать итератор - и затем родительский цикл будет увеличивать его снова (!), в конечном итоге делая шаг итераторачерез конец ().Т.е. было бы "end () + 1", если бы была такая вещь.Следовательно, родительский цикл выдает эту ошибку при следующей проверке.

Чтобы обойти это, я в итоге вставил эту строку после дочернего цикла:

`if (it == vStringList.end()) --it;`

Грязно, но работает: D

Я знаю, что это может быть очевидным для некоторых, но я какое-то время ломал голову над этим, смеется

2 голосов
/ 02 сентября 2011

Отправка этого сообщения только в том случае, если кто-то еще сталкивается с этой проблемой и пытается это решение, задаваясь вопросом, почему это не работает, вот реальное решение / объяснение.

@ Стив Джессоп - Ваш код содержит ошибки, и вы также получили егонаписано здесь ... (я также отредактировал его пост, чтобы исправить проблему, как только он будет утвержден, он будет исправлен в оригинальном посте)

http://techsoftcomputing.com/faq/3779252.html

Не знаюЧтобы понять, как это является «решением» проблемы, когда она создает новую проблему путем создания бесконечного цикла, в цикле while должен быть deleteIterator ++, чтобы он действительно достиг конца вектора.

ТакжеЯ столкнулся с этой проблемой, и мое решение было в цикле while, проверяющем, был ли итератор равен концу или размер вектора равен 0, и разрывался, прежде чем пытаться увеличить итератор.

Пример.

    std::vector<RankPlayer*>::iterator Rank_IT = CurrentPlayers.begin();

    while ( Rank_IT != CurrentPlayers.end() ) 
    {    
        RankPlayer* SelPlayer = (*Rank_IT);

        if( strstr( SelPlayer->GamerTag, this->GamerTag ) != NULL )
        {

            delete[] SelPlayer->PlayerData;
            delete[] SelPlayer;
            Rank_IT = CurrentPlayers.erase( Rank_IT );
        }

        if( Rank_IT == CurrentPlayers.end() || CurrentPlayers.size() == 0 )
        {
            break;
        }
            ++Rank_IT;
    }
1 голос
/ 23 сентября 2010

Этот код пропускает все содержимое вектора - вы также должны delete *deleteIterator в цикле. Вы можете избежать всего этого, используя Base вместо Base* в качестве содержимого vector, тогда clear() уничтожит их для вас. Или используйте boost::ptr_vector, который автоматизирует уничтожение, если вам нужны необработанные указатели.

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

1 голос
/ 23 сентября 2010

Любой итератор, указывающий на удаленный элемент или на элементы после удаляемого, становится недействительным при вызове метода стирания вектора. Метод Erase возвращает действительный итератор, указывающий на следующий элемент в векторе. Вы должны использовать этот итератор, чтобы продолжить цикл, а не увеличивать недействительный итератор. Вы также можете использовать метод clear для удаления всех элементов вектора. Тем не менее, вам нужно помнить, чтобы явно отменить выделенную память для элементов.

0 голосов
/ 23 сентября 2010

Векторные итераторы могут увеличиваться, но если вы удаляете элементы, содержимое вектора изменяется, и, следовательно, итератор становится недействительным.

Итак, если вы удаляете объекты, вы должны использовать возвращаемое значение erase(), которое дает вам следующий действительный итератор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...