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

182
30 июня 2019, 02:10

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

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

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

template<class FwdIt>
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<int> 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 знаю, но здесь он не годен.

Answer 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<class FwdIt>
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) можно сделать это более эффективно.
  • Более практичным вариантом было бы сразу передавать итератор на перемещаемый элемент.
Answer 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;
            }
        }
Answer 3

Ошибки в вашей функции очевидные, вам об этом рассказали в комментарих. Функция пишется просто:

template<class FwdIt>
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<class ClassType, class For = typename ClassType::iterator>
ClassType my_remove(ClassType& cont, For p, For q, const size_t n)
{
    if(typeid(typename std::iterator_traits<For>::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<int> 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;
}
READ ALSO
Преобразование Бокса — Мюллера

Преобразование Бокса — Мюллера

Хочу воспользоваться первым вариантом этого метода, чтобы генерировать псевдослучайные числа с нормальным распределением

119
Запрет ввода символов в Linux консоле на C++

Запрет ввода символов в Linux консоле на C++

как можно запретить ввод букв внутри терминала? Жмем клавишу, программа сразу отрабатывает, понимает, что это буква и ничего не происходитЖмем...

121
Internal error. MavenArchiver

Internal error. MavenArchiver

Получаю при интале вот такую ошибкукто знает как исправить?

114
Документация по наведению мыши

Документация по наведению мыши

Изучаю Spring на IDE IntelJIdeaХочу почитать что делает тот или иной метод, аннотация

133