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

问题描述 投票:9回答:1

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

因此,当前我必须传递我自己的迭代器,该迭代器本质上是一个boost::function_output_iterator,并且带有一个仅调用unorderedSet.insert(param1)的函子。

为什么std::inserter甚至requires hint迭代器参数呢?

c++ unordered-set invalidation insert-iterator
1个回答
0
投票

没有。之所以需要hint参数,是因为std::inserter用于在插入上下文中需要position的容器。如您所知,无序容器不是这种情况。

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)插入值pos之前3)插入值before pos >>的计数副本4)插入范围为[first,last)pos之前的元素。如果InputIt是整数类型,则此过载与过载(3)具有相同的效果。 (直到C ++ 11)仅在InputIt符合LegacyInputIterator的情况下,此重载才参与重载解析,以避免与重载(3)产生歧义。 (C ++ 11起)如果first和last是* this的迭代器,则该行为是不确定的。5)从初始化列表ilist 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无效。

© www.soinside.com 2019 - 2024. All rights reserved.