Страницы

Поиск по вопросам

среда, 1 января 2020 г.

Цикл for проходящий по итераторам

#cpp #cpp11


Проблема:
Синтаксическая конструкция цикла for для итераторов стандартна.

   // code
   for(auto it = p; it != q; ++it){...}
   // another code


И это, кажется, работало. Но я столкнулся с тем, что условие it != q не проходит
в коде ниже. Просто не срабатывает и происходит обращение за пределы контейнера. Знаю,
что end указывает ЗА последний элемент, но как это мешает работе? 

template
FwdIt remove_nth(FwdIt p, FwdIt q, size_t n)
{
// smth
        for (auto it = ++p; it != q;++it)
        {
            auto next = p; 
            *p = *++next; 
            p = next;
        }
//smth
}


Вызов происходит так:

std::vector v = {0,1,2,3,4,5,6,7,8,9,10};
v.erase(remove_nth(v.begin(), v.end(), 5), v.end());


Впорос: 
Что я делаю не так? Я пропустил что-то существенное в освоении работы с итераторами?
Про range-based знаю, но здесь он не годен.
    


Ответы

Ответ 1



remove_nth() переносит элемент, который n номера, в конец. erase подчищает его. Удалить N-й элемент вектора: v.erase(v.begin()+N); Удалить K элементов начиная с N-го v.erase(v.begin()+N, v.begin()+N+K); remove_nth() переносит элемент, который n номера, в конец. Как-то так: template FwdIt moveNToEnd(FwdIt p, FwdIt q, size_t n) { assert (std::distace (p,q) < n); std::advance (p, n); auto val = *p; FwdIt prev = p++; for (;p!= q;) { *prev++ = *p++; } *prev = val; return prev } Замечания: Для других контейнеров (std::list) можно сделать это более эффективно. Более практичным вариантом было бы сразу передавать итератор на перемещаемый элемент.

Ответ 2



Цикл можно было оформить так. Полностью соответствует требуемому. В std::cout отладочный вывод auto last = p; if (p != q) { for (auto it = ++p; it != q; ++it) { std::cout << " before: it " << *it << "; last " << *last << std::endl; std::swap(*last, *it); std::cout << "after: it " << *it << "; last " << *last << std::endl; ++last; p = it; } }

Ответ 3



Ошибки в вашей функции очевидные, вам об этом рассказали в комментарих. Функция пишется просто: template FwdIt remove_nth(FwdIt p, FwdIt q, const size_t n) { FwdIt first = p + n; // нужно сохранять значение начала `p` for (auto it = first + 1; it != q;++it) *first++ = *it; return first; } Я думаю вам нужна отдельная функция, не требующая дальнейшее использование методов контейнера для удаления элемента: Приведу пример: template ClassType my_remove(ClassType& cont, For p, For q, const size_t n) { if(typeid(typename std::iterator_traits::iterator_category) != typeid(std::random_access_iterator_tag) || size_t(q - p) <= n) return cont; For It = std::remove(p, q, n); //или используйте вашу собственную функцию // For It = remove_nth(p, q, n); return ClassType(p, It);; } int main() { std::vector v = {0,1,2,3,4,5,6,7,8,9,10}, res = my_remove(v, v.begin(), v.end(), 4); for (int i : res) cout << i << ' '; return 0; }

Комментариев нет:

Отправить комментарий