4

Suppose I have a class encapsulating std container:

class Stash
{
    list<int> Data;

public:
    list<int>::const_iterator GetAccess() const { return Data.begin(); }
};

It's very convenient way of forcing the user to read the data in form of the iterator. However, I can't find the way other that comparing the iterator to container.end(). So, I would like to know if there's an option to do it solely by stdlib or I have to write iterator class myself (with can_advance method, for example).

Relevant question might be this one, but it asks whether the iterator is valid, not whether it can advance. I weren't able to find any information about the latter.

Community
  • 1
  • 1
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135

3 Answers3

4

You can't do this, a single iterator does not contain the information when it is at the end of the sequence its pointing into.

Normally, this is solved by either providing a range (think std::make_pair(cont.begin(), cont.end())), or providing begin() and end() methods to your class, effectively making it a range.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Can I safely compare to the stored `.end()` later on? I mean, is it always valid, even if the container's items change? – Bartek Banachewicz Aug 15 '12 at 14:43
  • 3
    @Bartek: Depends on the container's iterator invalidation semantics. With `std::list`, it's fine. However, you shouldn't modify the container while iterating over it, that is normally considered *bad*. – Xeo Aug 15 '12 at 14:44
2

Iterators work in pairs: an iterator that points to the beginning of a sequence and an iterator that points past the end of the sequence. That's why all the containers have begin() and end() member functions: so you can look at the sequence of values that the container manages.

It would be far more idiomatic to change the name of GetAccess to begin and to add end. Having end() would also make it possible to apply standard algorithms to the data.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

What you seem to be asking for is a "lookahead" iterator. You could write a class to "adapt" an iterator to have lookahead, where the adaptor just stays one step ahead of your code:

template<class FwdIter>
class lookahead_iterator
{
public:
    lookahead_iterator(const FwdIter& begin): cur_iter(begin), next_iter(++begin) {}
    operator FwdIter() const { return cur_iter; }
    lookahead_iterator<FwdIter>& operator ++() { cur_iter = next_iter++; return *this; }
    // Other methods as needed.
private:
    FwdIter cur_iter;
    FwdIter next_iter;
};

Needless to say, this gets a lot more complicated if you need more than a forward iterator.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
  • I suppose `operator FwdIter() const { return cur_iter; }` was to be either `operator FwdIter ...` or `FwdIter operator() ...` – Bartek Banachewicz Aug 16 '12 at 07:17
  • It's supposed to be an overload for the typecast operator, invoked by explicit or implicit `static_cast(my_lookahead_operator)` or `(FwdIter)my_lookahead_operator`. It's definitely not `operator()`. – Mike DeSimone Aug 16 '12 at 12:38
  • I'm not sure what you mean. See http://www.learncpp.com/cpp-tutorial/910-overloading-typecasts/ for an intro on overloading typecast operators. – Mike DeSimone Aug 16 '12 at 13:25