c++ - std::为无序集(或映射)插入迭代器?

标签 c++ unordered-set invalidation insert-iterator

std::中是否有插入迭代器?对于无序集合?据我所知,std::inserter需要一个迭代器参数。这对于无序容器(至少对于 boost::unordered_set )是不安全的,因为它们可能会在 insert 期间重新分配操作并渲染通过的 .begin()迭代器无效。

所以目前我必须传递我自己的迭代器,它本质上是一个 boost::function_output_iterator使用一个简单地调用 unorderedSet.insert(param1) 的仿函数.

为什么会这样std::inserter甚至需要 hint迭代器参数呢?

最佳答案

没有。 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)

Inserts elements at the specified location in the container.

  1-2) inserts value before pos
  3) inserts count copies of the value before pos
  4) inserts elements from range [first, last) before pos.
       This overload has the same effect as overload (3) if InputIt is an integral type. (until C++11)
       This overload only participates in overload resolution if InputIt qualifies as LegacyInputIterator, to avoid ambiguity with the overload (3). (since C++11) The behavior is undefined if first and last are iterators into *this.
  5) inserts elements from initializer list ilist before pos.



我知道这不是您要寻找的答案,但是推出自己的答案很容易,即使不是有点冗长:
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);
    });
}

Live on Godbolt

这里要注意的一点是,你的断言通过了这个 hint无序容器不安全的论点是错误的。当operator=被调用,一个新元素被插入到容器中,iter成员更新为任何 insert返回。由于此值必须有效,因此 iter 不可能可能永远无效。

关于c++ - std::为无序集(或映射)插入迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27429705/

相关文章:

c++ - char指针不递增?

C++ 正在使用 [](int i){return i;} 作为 unordered_set 散列函数的好习惯吗?

mysql - 如何用mysql使redis缓存失效?

c++ - 使用 Qt 挂载网络驱动器

C++ 预期主表达式编译错误

c++ - 为什么我的蛇只向上移动?

c++ - C++ 中无序关联容器的哈希函数

c++ - 将 vector move 到 unordered_set

java - 如何使浏览器 session 无效

java httpSession 在处理时失效