Как увеличить итератор на 2? - PullRequest
61 голосов
/ 29 июня 2009

Может кто-нибудь сказать мне, как увеличить итератор на 2?

iter++ доступно - нужно ли делать iter+2? Как мне этого добиться?

Ответы [ 8 ]

93 голосов
/ 29 июня 2009

std::advance( iter, 2 );

Этот метод будет работать для итераторов, которые не являются итераторами с произвольным доступом, но его реализация может быть специализированной, чтобы быть не менее эффективной, чем iter += 2 при использовании с итераторами с произвольным доступом.

26 голосов
/ 29 июня 2009

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n);

где n в вашем случае равно 2.

Прелесть этой функции в том, что если "it" является итератором с произвольным доступом, быстрый

it += n

используется операция (то есть vector <,,> :: iterator). В противном случае он отображается на

for(int i = 0; i < n; i++)
    ++it;

(т.е. список <..> :: итератор)

16 голосов
/ 07 сентября 2015

Если у вас нет модифицируемого lvalue итератора, или вы хотите получить копию данного итератора (оставив исходный без изменений), то C ++ 11 поставляется с новыми вспомогательными функциями - std::next / std::prev:

std::next(iter, 2);          // returns a copy of iter incremented by 2
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2
std::prev(iter, 2);          // returns a copy of iter decremented by 2
7 голосов
/ 29 июня 2009

Вы можете использовать оператор «присваивание путем сложения»

iter += 2;
4 голосов
/ 29 июня 2009

Если вы не знаете, достаточно ли у вас следующих элементов в вашем контейнере или нет, вам нужно проверять конец контейнера между каждым шагом. Ни ++, ни std :: advance не сделают этого за вас.

if( ++iter == collection.end())
  ... // stop

if( ++iter == collection.end())
  ... // stop

Вы можете даже свернуть свою собственную функцию безопасного перехвата.

Если вы уверены, что не дойдете до конца, лучшим решением будет std :: advance (iter, 2).

2 голосов
/ 09 декабря 2015

Мы можем использовать как std :: advance , так и std :: next , но между ними есть разница.

advance изменяет свой аргумент и ничего не возвращает. Так что его можно использовать как:

vector<int> v;
v.push_back(1);
v.push_back(2);
auto itr = v.begin();
advance(itr, 1);          //modifies the itr
cout << *itr<<endl        //prints 2

next возвращает измененную копию итератора:

vector<int> v;
v.push_back(1);
v.push_back(2);
cout << *next(v.begin(), 1) << endl;    //prints 2
0 голосов
/ 03 сентября 2017

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

static constexpr auto step = 2;

// Guard against invalid initial iterator.
if (!list.empty())
{
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step))
    {
        // do stuff...

        // Guard against advance past end of iterator.
        if (std::distance(it, list.end()) > step)
            break;
    }
}

В зависимости от реализации коллекции вычисление расстояния может быть очень медленным. Ниже это оптимально и более читабельно. Закрытие может быть изменено на шаблон утилиты с конечным значением списка, передаваемым константной ссылкой:

const auto advance = [&](list_type::iterator& it, size_t step)
{
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i);
};

static constexpr auto step = 2;

for (auto it = list.begin(); it != list.end(); advance(it, step))
{
    // do stuff...
}

Если циклов нет:

static constexpr auto step = 2;
auto it = list.begin();

if (step <= list.size())
{
    std::advance(it, step);
}
0 голосов
/ 29 июня 2009

Очень простой ответ:

++++iter

Длинный ответ:

Вы действительно должны привыкнуть писать ++iter вместо iter++. Последний должен возвращать (копию) старого значения, которое отличается от нового значения; это занимает время и пространство.

Обратите внимание, что приращение префикса (++iter) принимает значение l и возвращает значение l, тогда как приращение постфикса (iter++) принимает значение l и возвращает значение r.

...