【问题标题】:Splitting range into sub-ranges将范围拆分为子范围
【发布时间】:2010-11-09 23:16:32
【问题描述】:

我有一个容器 std::vector,我想有效地将​​它拆分为子范围,每个子范围都有 x 项。不需要原始容器,因此项目应该被移动而不是复制到子范围中。

我已经设法使用复制进行拆分,但是我不确定如何使用移动分配进行拆分?

    range.insert(range.end(), new_items.begin(), new_items.end());
    while(range.size() >= x)
    {
        sub_ranges.push_back(std::vector<int>(range.begin(), range.begin() + x));
        range = std::vector<int>(range.begin() + x, range.end());
    }

编辑:

有些进展……还是不完全,而且有点难看

    while(range.size() >= x)
    {
        std::vector<short> sub_range(x); // Unnecessary allocation?
        std::move(range.begin(), range.begin() + x, sub_range.begin());
        sub_ranges_.push_back(std::move(sub_range));

        std::move(range.begin() + x, range.end(), range.begin());
        range.resize(range.size() - x);
    }

【问题讨论】:

    标签: c++ c++11 range move move-semantics


    【解决方案1】:

    一个问题:你听说过View这个概念吗?

    这个想法是,您只需创建一个“视图”(代理模式)来限制/改变您对它的看法,而不是实际移动数据。

    例如,对于一个范围,一个非常简单的实现是:

    template <typename Iterator>
    struct Range
    {
      Iterator mBegin, mEnd;
    };
    

    Boost.Range 提供了一个胖版本,有很多东西。

    在这种情况下,优点很多。其中:

    • 单个vector,因此内存局部性更好
    • 拆分很简单,不涉及数据的任何移动/复制

    这里是split这个方法:

    typedef Range<std::vector<int>::iterator> range_type;
    
    std::vector<range_type> split(std::vector<int> const& range, size_t x)
    {
      std::vector<range_type> subRanges;
      for (std::vector<int>::iterator it = range.begin(), end = range.end();
           it != end; it += std::min(x, (size_t)std::distance(it,end)))
      {
        subRanges.push_back(range_type(it,end));
      }
      return subRanges;
    }
    

    当然,这只有在您可以保留 range 对象的情况下才有效。


    关于您的原始算法:while 循环的使用在这里是虚假的,并迫使您使用比必要更多的moves。我制作的for 循环在这方面应该会好很多。

    【讨论】:

    • subRanges.push_back(range_type(it,end)); 正确吗? range_type 似乎没有一个需要两个迭代器的 ctor。
    【解决方案2】:

    您可以在&lt;iterator&gt; 中使用std::make_move_iterator 将您的迭代器包装到move_iterator 中。此迭代器将std::move 解引用其基迭代器的结果,从而允许将其移至其他地方。

    // assuming I understand your code, which I don't
    range.insert(range.end(), new_items.begin(), new_items.end());
    while(range.size() >= x)
    {
        auto first = std::make_move_iterator(range.begin());
        auto last = std::make_move_iterator(range.begin() + x);
    
        sub_ranges.push_back(std::vector<int>(first, last));
        range = std::vector<int>(range.begin() + x, range.end());
    }
    

    编辑:就像你发现的那样,std::move()make_move_iterator 之间有一个映射:

    std::move(first, last, out); // is the same as
    std::copy(std::make_move_iterator(first), std::make_move_iterator(last), out);
    

    因此,您发现哪个更清洁取决于您。 (对我来说是第一个。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-28
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多