std:: insert итератор для неупорядоченных множеств (или карт)?

Есть ли итератор вставки в std:: для неупорядоченных множеств? Насколько я вижу, std::inserter требует аргумент итератора. Это небезопасно для неупорядоченных контейнеров (по крайней мере, для boost::unordered_set), потому что они могут перераспределить во время insert операция и рендеринг пройденного .begin() неверный итератор.

Так что в настоящее время я должен пройти свой собственный итератор, который по сути является boost::function_output_iterator с функтором, который просто вызывает unorderedSet.insert(param1),

Почему это так std::inserter даже требует hint аргумент итератора в любом случае?

0 ответов

Нет. Причина, по которойhint требуется аргумент, что std::inserterпредназначен для контейнеров, в которых требуется позиция в контексте вставки. Как вы знаете, это не относится к неупорядоченным контейнерам.

vector в примере контейнера, где знание positionэто требование для вставки. Из cppreference:

(1)
iterator insert( iterator pos, const T& value ); // (until C++11)
iterator insert( const_iterator pos, const T& value ); // (since C++11)

 (2)
iterator insert( const_iterator pos, T&& value ); // (since C++11)

(3)     
void insert( iterator pos, size_type count, const T& value ); // (until C++11)
iterator insert( const_iterator pos, size_type count, const T& value ); // (since C++11)

(4)     
template< class InputIt >
void insert( iterator pos, InputIt first, InputIt last); // (until C++11)
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last ); // (since C++11)

(5)
iterator insert( const_iterator pos, std::initializer_list<T> ilist ); // (since C++11)

Вставляет элементы в указанное место в контейнере.

1-2) вставляет значение перед поз.
  3) вставляет количество копий значения перед поз.
  4) вставляет элементы из диапазона [первый, последний) перед поз.
       Эта перегрузка имеет тот же эффект, что и перегрузка (3), если InputIt является интегральным типом. (до C++11)
       Эта перегрузка участвует в разрешении перегрузки, только если InputIt квалифицируется как LegacyInputIterator, чтобы избежать неоднозначности с перегрузкой (3). (начиная с C++11) Поведение не определено, если first и last являются итераторами в * this.
  5) вставляет элементы из списка инициализаторов ilist перед поз.


Я знаю, что это не тот ответ, который вы ищете, но развернуть свой собственный достаточно просто, если не сказать многословно:

template<typename Container>
class unordered_inserter {
public:
    using iterator_category = std::output_iterator_tag;
    using value_type = void;
    using reference_type = void;
    using difference_type = void;
    using pointer = void;
    using reference = void;
    using container_type = Container;

    unordered_inserter& operator++() {return *this;} //no-op
    unordered_inserter& operator++(int) {return *this;} //no-op
    unordered_inserter& operator*() {return *this;} //no-op
    constexpr unordered_inserter& operator=(const typename Container::value_type& value) {
        container->insert(value);
        return *this;
    }
    constexpr unordered_inserter& operator=(typename Container::value_type&& value) {
        container->insert(std::move(value));
        return *this;
    }
    unordered_inserter(Container* container)
        :    container(container)
    {}
protected:
    Container* container;
};

Вероятно, это можно будет отредактировать для поддержки других видов вставки, но я думаю, что пока этого достаточно.

Вот я немного поиграю с этим:

int main() {
    std::unordered_map<int, int> m;
    std::istringstream iss("1 2 3 4 5 6");

    std::transform(std::istream_iterator<int>(iss), std::istream_iterator<int>(), unordered_inserter(&m), [](int v) {
        return decltype(m)::value_type{v, v*v};
    });
    std::transform(m.begin(), m.end(), std::ostream_iterator<std::string>(std::cout, "\n"), [](auto pair) {
        return std::to_string(pair.first) + "," + std::to_string(pair.second);
    });
}

Живи на Godbolt


Здесь следует отметить, что ваше утверждение о том, что hintаргумент для неупорядоченных контейнеров небезопасен, неверен. когдаoperator= вызывается, и новый элемент вставляется в контейнер, iter член обновлен до любого insertвозвращается. Поскольку это значение должно быть действительным, нет возможности, чтобыiter когда-либо может быть признан недействительным.

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