Могу ли я увеличить итератор, просто добавив число? - PullRequest
41 голосов
/ 23 июня 2009

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

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

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

Это работает для меня (g ++), но я не уверен, гарантируется ли работа.

Ответы [ 3 ]

46 голосов
/ 23 июня 2009

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

C ++ 11 note

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

2 голосов
/ 23 июня 2009

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

0 голосов
/ 21 февраля 2019

Тонкий момент заключается в том, что 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());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...