Подтвердить что ты не робот

Std:: advance поведение при продвижении за пределы контейнера

Каково поведение std:: advance, когда вы говорите:

std::vector<int> foo(10,10);
auto i = foo.begin();
std::advance(i, 20);

Каково значение i? Это foo.end()?

4b9b3361

Ответ 1

Вы передаете размер foo, продвигаясь на 20-ю позицию. Определенно это не конец вектора. Он должен вызывать поведение undefined при разыменовании, AFAIK.

Изменить 1:

#include <algorithm>
#include <vector>
#include <iostream>

int main()
{
     std::vector<int> foo(10,10) ;
     std::vector<int>::iterator iter = foo.begin() ;
     std::advance(iter,20);

     std::cout << *iter << "\n" ;

     return 0;
}

Выход: 0

Если это последний элемент вектора, тогда он должен был дать 10 на разыменование итератора. Итак, это UB.

Результаты IdeOne

Ответ 2

Стандарт определяет std::advance() в терминах типов итератора, в котором он используется (24.3.4 "Операции итератора" ):

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

Требования к этим операциям на разных типах итераторов также указаны в стандарте (в таблицах 72, 74, 75 и 76):

  • Для итератора ввода или пересылки

    ++r precondition: r is dereferenceable
    
  • для двунаправленного итератора:

    --r precondition: there exists s such that r == ++s
    
  • Для итераторов с произвольным доступом операции +, +=, - и -= определяются в терминах префиксов двунаправленного и прямого итератора ++ и --, поэтому те же предпосылки сохраняются.

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

Поскольку это поведение undefined вы не можете "ожидать" чего-либо в частности. Но вы, вероятно, столкнетесь в какой-то момент (надеюсь, скорее раньше, чем позже, так что вы можете исправить ошибку).

Ответ 3

В соответствии со стандартом С++ и 24.3.4 std::advance(i, 20) действует тот же эффект, что и for ( int n=0; n < 20; ++n ) ++i; для положительного n. С другой стороны (& sect; 24.1.3), если i является сквозным, то операция ++i undefined. Таким образом, результат std::advance(i, 20) равен undefined.

Ответ 4

На странице SGI для std:: advance:

Каждый итератор между я и я + n (включительно) неособо.

Поэтому я не является foo.end(), а разыменование приведет к поведению undefined.

Примечания:

  • См. этот вопрос для получения более подробной информации о том, что (не) сингулярно означает при обращении к итераторам.
  • Я знаю, что страница SGI не является стандартом де-факто, но в значительной степени все реализации STL следуют этим рекомендациям.

Ответ 5

Это, вероятно, поведение undefined. Единственное, что говорится в стандарте:

Поскольку только итераторы произвольного доступа предоставляют операторы + и -, библиотека предоставляет два шаблона функций вперед и расстояние. Эти шаблоны функций используют + и - для итераторов произвольного доступа (и, следовательно, для них постоянное время); для входных, прямых и двунаправленных итераторов они используют ++ для обеспечения линейных временных реализаций.

template <class InputIterator, class Distance> 
void advance(InputIterator& i, Distance n);

Требуется: n должно быть отрицательным только для итераторов с двунаправленным и случайным доступом. Эффекты: Приращения (или уменьшения для отрицательного n) ссылки итератора я на n.