0

我有一个容器 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);
    }
4

2 回答 2

3

一个问题:你听说过这个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循环是虚假的,并迫使您使用move比必要更多的 s 。我制作的for循环在这方面应该要好得多。

于 2010-11-10T08:09:41.870 回答
1

您可以使用std::make_move_iteratorin<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);

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

于 2010-11-09T23:19:56.357 回答