#cpp #cpp11
Проблема: Синтаксическая конструкция цикла for для итераторов стандартна. // code for(auto it = p; it != q; ++it){...} // another code И это, кажется, работало. Но я столкнулся с тем, что условие it != q не проходит в коде ниже. Просто не срабатывает и происходит обращение за пределы контейнера. Знаю, что end указывает ЗА последний элемент, но как это мешает работе? templateFwdIt 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 номера, в конец. Как-то так: templateFwdIt 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
Ошибки в вашей функции очевидные, вам об этом рассказали в комментарих. Функция пишется просто: templateFwdIt 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; }
Комментариев нет:
Отправить комментарий