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

86 Views Asked by At

I'm writing a custom container that internally uses a std::deque for its implementation. I want the container to support range-based for loops so implemented the begin() and end() functions. I don't want to expose the std::deque::iterator as the return value for begin() and end() so I wrote my own iterator in the custom container to return.

My iterator constructs via a pointer to the type that the custom container holds so I can dereference the deque::begin() iterator to construct. But I can't deference deque::end() because it's undefined behaviour (although if I swap deque for vector it does work, but I imagine this is because of contiguous memory).

How do I properly wrap std::deque in this instance to be able to properly identify the end() of the container?

I could just implement this with a vector and implement the necessary PushFront() operation but I think it's an interesting question.

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_;
};

0

There are 0 best solutions below