如何包装不使用连续内存的 STL 容器迭代器?

How can I wrap STL container iterators that don't use contiguous memory?

提问人:DWil 提问时间:7/31/2023 最后编辑:DWil 更新时间:7/31/2023 访问量:75

问:

我正在编写一个自定义容器,该容器在内部使用 a 来实现。我希望容器支持基于范围的循环,因此实现了 and 函数。我不想公开 作为返回值,所以我在自定义容器中编写了自己的迭代器来返回。std::dequeforbegin()end()std::deque::iteratorbegin()end()

我的迭代器通过指向自定义容器所包含类型的指针进行构造,因此我可以取消引用要构造的迭代器。但我不能尊重,因为它是未定义的行为(尽管如果我换成它确实有效,但我想这是因为连续记忆)。deque::begin()deque::end()dequevector

如何正确包装此实例,以便能够正确识别容器?std::dequeend()

我可以用一个向量来实现它并实现必要的操作,但我认为这是一个有趣的问题。PushFront()

struct Foo;

// Example custom container
class FooQueue{
public:

  FooId PushFront(Foo& foo);
  FooId PushBack(Foo& foo);
  void RemoveFoo(FooId id);

  // Custom iterator
  struct Iterator{
    using iterator_category = std::random_access_iterator_tag;
    using difference_type = std::ptrdiff_t;
    using value_type = Foo;
    using pointer = value_type*;
    using reference = value_type&;

    explicit Iterator(pointer ptr) : ptr_(ptr){

    Iterator& operator++()
    {
      ptr_++;
      return *this;
    }

    Iterator operator++(int)
    {
      Iterator tmp = *this;
      ptr_++;
      return tmp;
    }

    friend bool operator==(const Iterator& lhs, const Iterator& rhs){ return lhs.ptr_ == rhs.ptr_ };
    friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return !(lhs == rhs); }
  private:
    pointer ptr_;
  };

  Iterator begin(){ return Iterator(&(*deque_.begin())); }
  Iterator end() { return Iterator(&(*deque_.end())); } /* !!! Undefined behavior: Not allowed to
  dereference .end() !!! */
private:
  std::deque<Foo> deque_;
};

C++ 迭代器 deque

评论

4赞 Some programmer dude 7/31/2023
你为什么不让你的迭代器包装,就像你的容器包装一样?然后迭代器的“指针”是 .然后,所有迭代器函数和运算符都将是 deque 迭代器函数和运算符的简单包装器。std::deque::iteratorstd::dequestd::deque::iterator
3赞 Toby Speight 7/31/2023
您甚至可以在类中,这样源代码就不会受到基础容器更改的影响,但不必自己实现迭代器。using iterator = std::deque::iterator; using const_iterator = std::deque::iterator;
0赞 DWil 7/31/2023
我只是尝试包装 std::d eque::iterator,它运行良好。我想得太复杂了,所以@Someprogrammerdude感谢。
0赞 DWil 7/31/2023
@TobySpeight 别名迭代器是否仍然会暴露类型,因此我必须导出 std::d eque::iterator(我试图避免)?
1赞 chrysante 7/31/2023
@DWil 这取决于你所说的“出口”是什么意思。如果将类型从更改为类的用户,则必须重新编译,但无论哪种方式都是如此。问题是,如果使用 ,迭代器的 是 。如果取消引用迭代器,例如在基于 for 循环 () 的范围内,则 是 type 而不是 .如果希望迭代器取消引用指针,则必须编写一个包装迭代器来执行此操作。std::dequestd::vectorusing Iterator = std::deque<Foo*>::iteratorvalue_typeFoo*for (auto& f: myFooQueue) { ... }fFoo*Foo&

答: 暂无答案