Итератор C ++ случайно становится недействительным - PullRequest
2 голосов
/ 06 декабря 2011

Я потерян: итератор вектора из std :: string работает отлично, если только перед ним нет вызова функции (Z_UB-> set ()) ++. Вот код:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
it++;
std::cout << "second of vector: " << *it << std::endl;

создает следующий вывод

begin of vector: scn1

Однако, если я переместу вызов функции так:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
it++;
std::cout << "second of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);

Результатом является следующее ожидаемое поведение:

begin of vector: scn1
second of vector: scn2

Внутри функции Z_UB-> set () ничего не осталось, кроме самого вызова:

void Parameter::set( std::string _i, std::string _j, float value) {
//int i = indexSets[0]->backIndex(_i);
//int j = indexSets[1]->backIndex(_j);

//data2D[0][0] = value;
}

Так что, если я вызову функцию Z_UB-> set () после того, как я создал итератор, доступ к нему приведет к сбою программы. Что-то жизненно важное, что я пропустил в Итераторах?

Ответы [ 4 ]

2 голосов
/ 06 декабря 2011

Если g_SPP является глобальной переменной, то итераторы над ней будут аннулированы любой мутирующей операцией.


Обновление - это из спецификации ISO / ANSI 1998 года:

Следующее делает недействительными все ссылки, итераторы и указатели, ссылающиеся на элементы последовательности, если требуется выделение. Выделение требуется, если текущий capacity() меньше целевого размера вектора.

  • void reserve(size_type n)
  • iterator insert(iterator position, const T& x)
  • void insert(iterator position, size_type n, const T& x)
  • void insert(iterator position, InputIterator first, InputIterator last) и

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

  • iterator erase(iterator position)
  • iterator erase(iterator first, iterator second)

Изменение размера вектора эквивалентно вызову либо insert, либо erase. Согласно 23.2.4.2/6: resize(sz, c=value_type()) имеет тот же эффект, что и:

if (sz > size())
    insert(end(), sz - size(), c);
else if (sz < size())
    erase(begin() + sz, end());
else
    ;
2 голосов
/ 06 декабря 2011

Несколько возможностей:

  • Либо у вас нет хорошего воспроизводимого примера: возможно, при первом запуске у вас был только один элемент в векторе (как он заполнен?), И вы вызвали неопределенное поведение, поскольку вы не проверяли it против g_SPP.scenarios->getVector().end()
  • Или Z_UB->set не делает то, что вы думаете. Это полиморфный класс? set виртуально? Оператор -> перегружен?
  • Является ли ваше приложение многопоточным, а другой поток изменяет ваш контейнер?
1 голос
/ 07 декабря 2011

.getVector () вернул копию вектора.Сравнение итератора с конечной точкой итератора совершенно другого объекта не имеет смысла.Возврат ссылки решил проблему.

@ Xeo также указал на гораздо лучшее объяснение: при создании итератора из копии, подобной этой:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();

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

1 голос
/ 06 декабря 2011

a std::vector<T>::iterator будет недействительным, если вы добавляете или удаляете элементы во время итерации по нему, если вектор должен сам изменить свой размер при добавлении элемента.

...