Baz
Baz

Reputation: 13123

Get last item from input iterator

Is this correct behaviour for an input iterator, with regard to accessing the last item:

for(i=being();i!=end();i++){}
std::string s = i->toString();
return s;

Or should it throw an exception if I try to do this?

My iterator makes use of two c function calls: getFirst(...) and getNext(...)

Upvotes: 0

Views: 285

Answers (4)

jpalecek
jpalecek

Reputation: 47762

The behavior is undefined, and you needn't do anything about it while implementing your iterator (no need to even throwing an exception). When implementing InputIterators, you only have to implement the operations

  • iter == iter2, iter != iter2
  • *iter, iter->...
  • ++iter, (void)iter++
  • *r++

Of those, only the last one is hard (you have to return data from the previous position, while the iterator is moved to the next). It is typically implemented by a proxy, that remembers the old data.

Upvotes: 0

kennytm
kennytm

Reputation: 523224

This is not a correct behavior. The standard convention in C++ is that, end() should point to the place beyond the last item. Dereferencing it will cause undefined behavior (C++11 §24.2.2/5) in general.

You may make your own iterator to forgive dereferencing end() and exploit this, but it deviates from the standard practice, and make it hard for people to understand your code. I suggest you to throw an exception instead of returning the last item.


In standard C++, if all you have is a non-reproducible input iterator, it's not possible to "get the last item" unless you extract it every time:

auto it = begin();
auto val;
while (it != end()) {
    val = *it;
    ++ it;
}
return val;

But if you can create a forward iterator, then you could use

auto iter = begin();
decltype(iter) last_iter;
while (true) {
    last_iter = iter++;
    if (iter == end())
        break;
}
return last_iter;

Or if you creating the input iterator twice is cheap, you could do the iteration twice:

auto dist = std::distance(begin(), end());
auto last_iter = begin();
std::advance(last_iter, dist - 1);
return last_iter;

Upvotes: 2

cppanda
cppanda

Reputation: 1315

as far as stl containers are concerned, it is not correct behavior.

end()

Returns an iterator referring to the past-the-end element in the list container.

which would mean that after your loop, i does not point to a correct object (NOT the last element), but rather to a special defined end value, which would result in a access violation on calling i->toString().

Upvotes: 0

jrok
jrok

Reputation: 55395

No, this is not OK, you'll be dereferencing end() and invoking undefined behaviour. Consider:

int main()
{
    int i = 0;
    for (; i < 42; ++i) ;
    std::cout << i;    // prints 42, did you expect 41?
}

Unless of course, you implemented your iterator class to do something sensible in this case. This not ok for standard library iterators, however.

Upvotes: 0

Related Questions