Действителен ли back_insert_iterator на протяжении всего времени существования контейнера?

Думаю, я знаю ответ на этот вопрос, но был бы признателен за проверку здравомыслия.

Применяется ли аннулирование итератора к std::back_insert_iterators?

#include <cassert>
#include <iterator>
#include <vector>

int main() {
    auto v = std::vector<int>{ 0, 1, 2 };
    auto iter = std::back_inserter(v);
    *iter++ = 3;
    v.clear();    // invalidates iterators, but
    *iter++ = 4;  //  back_insert_iterator is special?
    assert(v.size() == 1 && v[0] == 4);
    return 0;
}

Этот код работает для меня, потому что реализация std::back_insert_iterator от моего поставщика не содержит итератора (или указателя или ссылки). Он просто вызывает метод push_back контейнера.

Но требует ли стандарт такой реализации? Может ли back_insert_iterator другого поставщика содержать и поддерживать итератор «один за конец», который можно использовать при вызове метода вставки контейнера? Кажется, это соответствует требованиям. Эта разница, конечно, состоит в том, что оно может быть признано недействительным.


Я знаю, что cppreference.com не является авторитетным, но он более доступен, чем стандартный.

[Метод очистки вектора] [i]nпроверяет любые... итераторы, ссылающиеся на содержащиеся элементы. Любые итераторы, прошедшие мимо конца, также становятся недействительными. [cppreference.com, курсив добавлен]

std::back_insert_iterator может быть дочерним элементом итератора прошедшего конца.

итератор обратного вставки не ссылается ни на какие элементы вектора, он просто ссылается на вектор. * вызывает push_back и ++ не работает: en.cppreference.com/w/cpp/iterator/back_insert_iterator

NathanOliver 06.07.2024 18:58

@NathanOliver: это =, который вызывает push_back, * тоже не работает.

Jarod42 06.07.2024 19:01

@Jarod42 Jarod42 Ага, да, * для обычных итераторов ввода.

NathanOliver 06.07.2024 19:02

«std::back_insert_iterator может быть дочерним элементом итератора, прошедшего конец». -- Не согласно cppreference на странице std::end (курсив добавлен): «Возвращает c.end(), который обычно представляет собой итератор, следующий за концом последовательности, представленной c». Во фразе используется слово «конец», как, вероятно, использовал бы человек до изучения итераторов; он рассматривает «конец» как последний элемент, а не как результат вызова end(). Фразу было бы точнее сказать «элемент, прошедший за конец», но эта формулировка непопулярна.

JaMiT 06.07.2024 19:50

Может ли back_insert_iterator другого поставщика содержать и поддерживать итератор «один за концом», который можно использовать с вызовом метода вставки контейнера? Кажется, это соответствует требованиям. - Как бы это работало, если бы back_inserter вызывали дважды подряд? В этом отношении std::inserter более интересен — вы передаете ему итератор.

Evg 06.07.2024 20:28

@Evg: Схема *it++ = value;. Простая реализация рассматривает приращение как неактивное. Реализация, которая «удерживает и поддерживает» итератор, фактически будет выполнять приращение.

Adrian McCarthy 07.07.2024 07:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
6
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

За [back.insert.iterator]

namespace std {
  template<class Container>
  class back_insert_iterator {
  protected:
    Container* container;

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    constexpr explicit back_insert_iterator(Container& x);
    constexpr back_insert_iterator& operator=(const typename Container::value_type& value);
    constexpr back_insert_iterator& operator=(typename Container::value_type&& value);

    constexpr back_insert_iterator& operator*();
    constexpr back_insert_iterator& operator++();
    constexpr back_insert_iterator  operator++(int);
  };
}

constexpr explicit back_insert_iterator(Container& x);

1 Эффекты: инициализирует container с помощью addressof(x).

constexpr back_insert_iterator& operator=(const typename Container::value_type& value);

2 эффекта: Как будто автор: container->push_back(value);

3 возврата: *this.

constexpr back_insert_iterator& operator=(typename Container::value_type&& value);

4 эффекта: Как будто автор: container->push_back(std​::​move(value));

5 Возвратов: *this.

[...]

Как мы видим, итератор получает указатель на контейнер, а затем push_back вызывается непосредственно в контейнере, поэтому никаких шансов на UB нет.

Другие вопросы по теме