Вопрос по c++ – Могу ли я увеличить итератор, просто добавив число?

39

Могу ли я сделать обычные вычисления с итераторами, то есть просто увеличить его, добавив число?

В качестве примера, если я хочу удалить элементvec[3], я могу просто сделать это:

<code>std::vector<int> vec;
for(int i = 0; i < 5; ++i){
      vec.push_back(i);
}
vec.erase(vec.begin() + 3); // removes vec[3] element
</code>

Это работает для меня (g ++), но я не уверен, что это Гарантировано работать

Ваш Ответ

3   ответа
45

если итератор является итератором произвольного доступа, итераторами этого вектора являются (см.ссылк). Функция STLstd::advance можно использовать для продвижения общего итератора, но поскольку он не возвращает итератор, я склонен использовать +, если он доступен, потому что он выглядит чище.

C ++ 11 note

Теперь естьstd::next а такжеstd::prev, которыйделат верните итератор, так что если вы работаете в ленте шаблонов, вы можете использовать их для продвижения общего итератора и при этом иметь чистый код.

О, значит, это не сработает для std :: list? Frank
Нет, это не так. Оператор + означает «за один шаг, прыгнуть так далеко вперед», чего не может сделать итератор списка. Прямые итераторы без случайного доступа (например, итераторы списков) поддерживают только оператор приращения (++) для продвижения по одному элементу за раз. Как сказал Тодд, вы можете использовать std :: advance, который неоднократно вызывает оператор ++, чтобы кратко выразить идею перемещения неслучайного итератора вперед на несколько шагов. Tyler McHenry
Правильный; добавлены ссылки на документацию, в которых перечисляются, какие функции должны быть доступны для каких типов итераторов. Todd Gardner
Ну, чтобы быть педантичным, он не гарантированно работает для двунаправленных итераторов, таких как list, но я считаю, что это не гарантированно не будет работать; реализация может добавить его. Todd Gardner
Стоит отметить, что ошибка компиляции при использовании + с итератором std :: list являетсявыгод over std :: продвижение в некоторых ситуациях. Если вы продвигали произвольное количество мест в векторе (не только одно место, как здесь) и вам нужно делать это за постоянное время, тогда кто-то изменяет контейнер на список, это может быть ошибкой, которую вы хотите отловить. Лучше поймать его во время компиляции, чем когда вы заметите плохую производительность позже (возможно, на производстве!). Кроме того, использование + вместо std :: advance документирует ожидание того, что это операция постоянного времени. Jim Oldfield
2

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

0

Тонкий момент в том, чтоoperator+ беретDistance; т.е. целое число со знаком. Если вы увеличиваете итератор без знака, вы можете потерять точность и столкнуться с неожиданностью. Например, в 64-битной системе,

std::size_t n = (1 << 64) - 2;
std::vector<double> vec(1 << 64);
std::vector<double> slice(vec.begin() + n, vec.end());

ведет к неопределенному поведению. Сg++ илиclang, вы можете попросить компилятор предупредить вас о таких нежелательных преобразованиях с флагом предупреждения-Wsign-conversion это не является частью канонического-Wall или-Wextra.

Обходной путь - работать с указателем напрямую.

std::vector<double> slice(vec.data() + n, vec.data() + vec.size());

Это не красиво, но правильно. В некоторых случаях вам нужно создать итератор вручную, например,

std::vector<double>::iterator fromHere{vec.data() + n};
vec.erase(fromHere, vec.end());

Похожие вопросы