Round-Robin迭代器和STL的按值传递策略

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

我正在编写一个迭代器round_robin_iter,该迭代器会保留一堆迭代器。每当round_robin_iter递增时,它都会以循环方式递增当前迭代器并传递到下一个迭代器。这使我可以轻松地插入不同容器中的物品。但是,随着迭代器的数量不断增加,我无法再将STL的算法与round_robin_iter一起使用,因为在这种情况下,STL希望按值传递迭代器的价格很高。

解决这个问题的粗略想法是将reference_wrapper<rouund_robin_iter>按值传递给STL算法,但这对我来说似乎是一个肮脏的技巧。 STL当然可以为我的问题提供一些更优雅的解决方案,不是吗?

编辑:正如HolyBlackCat所指出的,reference_wrapper没有实现正确的接口,因此我将不得不围绕round_robin_iter的间接编写自己的包装器...

EDIT2:根据要求,以下是迭代器的大致框架:

template<class Iter>
struct round_robin_iterator
{
  using IterList = list<pair<Iter, Iter>>;
  using reference = typename iterator_traits<Iter>::reference;
  IterList others;
  typename IterList::iterator current = others.end();

  bool is_end() const { return current == others.end(); }

  void operator++() {
    if(!others.empty()) {
      if(++(current->first) == current->second)
        current = others.erase(current);
      else ++current;
      if(is_end()) current = others.begin();
    }
  }

  reference operator*() { return *(current->first); }

  void add_iters(const Iter& _begin, const Iter& _end) {
    others.emplace_back(_begin, _end);
    if(others.size() == 1) current = others.begin();
  }

  bool operator!=(const round_robin_iterator& rr_it) const {
    if(!is_end()){
      if(!rr_it.is_end()){
        return current != rr_it.current;
      } else return true;
    } else return !rr_it.is_end();
  }
};
c++ stl iterator
1个回答
0
投票

[从非常有用的评论到问题,我收集了以下内容,用于将“大量”迭代器传递给STL算法:

  • 如果不再需要迭代器,则将其移动(通过std::move(iter)
  • 如果我确实仍然需要迭代器,那么根据定义,在某个时候我需要两个不同的此类迭代器,因此无法避免复制]]
  • 将“状态”放在堆上并进行浅表复制似乎伪装成复制,而实际上是在移动(或者更糟糕的是,它具有诸如更改我没有碰到的迭代器的副作用)

  • 关于使用哪个容器存储迭代器的讨论,我已经使用以下基础容器在std::accumulateround_robin_iterators上做了一些基准测试(以及策略,针对到达其末端的迭代器该怎么做):

  1. std::list(O(1)删除)
  2. std::vector(O(n)擦除)
  3. std::deque(O(n)擦除)
  4. [std::vector(O(n)-跳过)
  5. [std::deque(O(n)-跳过)
  6. (抱歉未在基准中包含std::tuple版本,但我需要动态尺寸)

基准测试在(a)1个大(Z尺寸)+许多(X-1)个小(Y尺寸)范围内进行迭代,并在(b)许多(X)尺寸范围内逐渐增大(从Y到Z)进行迭代。没有副本(实际上,我删除了std::list版本的副本构造函数+副本分配),迭代器通过move传递。可以找到代码here,但要旨如下:

  • 存储对象的大小对相对性能几乎没有影响
  • std::list在这种设置下很难被击败,即使Y接近Z
  • [std::deque(删除)击败std::vector(删除)大约X> 100
  • (擦除)几乎总是跳动(跳过)
© www.soinside.com 2019 - 2024. All rights reserved.