【问题标题】:std::back_inserter for a std::set?用于 std::set 的 std::back_inserter?
【发布时间】:2010-10-28 20:09:55
【问题描述】:

我想这是一个简单的问题。我需要做这样的事情:

std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());

当然,std::back_inserter 不起作用,因为没有 push_back。 std::inserter 也需要迭代器?我没有用过std::inserter,所以我不知道该怎么办。

有人有想法吗?


当然,我的另一个选择是为s2 使用一个向量,然后稍后再对其进行排序。也许这样更好?

【问题讨论】:

    标签: c++ algorithm stl


    【解决方案1】:

    在 2016 年,有人提议使用“单参数 inserter 迭代器”。 https://isocpp.org/files/papers/p0471r0.html 。我找不到提案是否推进了。我觉得有道理。

    现在你可以让这个行为定义 maker 函数:

    template<class Container>
    auto sinserter(Container& c){
        using std::end;
        return std::inserter(c, end(c));
    }
    

    用作:

    std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});
    

    【讨论】:

    • 这是否适用于所有标准容器?它不适用于 std::forward_list(编译器错误是“forward_list 没有名为 'insert' 的成员”,在 insert_iterator::operator= 的实例化内部)。应该吗?
    • @DonHatch,任何有insert(和end)的东西。似乎forward_list 首先没有insert 操作,只有insert_after。我认为,即使改变了它也不能在结束后插入。你不能改用std::list 吗?
    • 当然,我个人不需要 std::forward_list。但我对通用的“如何将一个容器复制到另一个容器?”感兴趣。对于所有有意义的容器对。我目前的兴趣是使用通用容器分配器,例如 @HowardHinnant 的 short_alloc。
    • @DonHatch,问题是这个问题有很多变体。 (““我如何将一个容器复制到另一个容器?”)。例如,你想保留原始值,你想最小化分配等等。对于最简单的情况,我认为最好的答案是使用构造带有两个迭代器的容器(大多数容器都可以使用)。NewContaner new_container(old_other_container.begin(), old_other_container.end()).
    • 是的,std::set 不是 SequentialContainer,这很好:-) existing_list = std::list(c.begin(), c.end(), existing_list.get_allocator()) 非常好,我想这就是我的答案。干杯!
    【解决方案2】:

    set 没有push_back,因为元素的位置由集合的比较器确定。使用std::inserter 并通过.begin():

    std::set<int> s1, s2;
    s1 = getAnExcitingSet();
    transform(s1.begin(), s1.end(), 
              std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());
    

    然后插入迭代器将调用s2.insert(s2.begin(), x),其中x 是写入迭代器时传递给它的值。该集合使用迭代器作为插入位置的提示。你也可以使用s2.end()。

    【讨论】:

    • 既然inserter(vec, vec.end()) 也适用于向量,为什么有人首先使用 back_inserter?
    • @NHDaly:因为 back_inserter 更快
    • @marton78 但是如果有的话,它不应该只快一点吗?当不需要移动任何元素时,在向量上调用 insert 而不是 push_back 应该大致相同 (O(1))。
    • @FelixDombek 你是对的,它不会慢很多。 v.insert(x, v.end()) 将在开头有一个额外的分支(由于它移动了 n 个元素,但这里 n 为零)。然而,使用inserter 1) 与使用push_back 2) 传达不同的意图是不寻常的,并使读者停下来认为 3) 是过早的悲观。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2011-01-19
    • 2011-05-16
    • 1970-01-01
    • 2014-12-06
    • 2020-04-04
    • 2023-04-05
    相关资源
    最近更新 更多