12

Does the C++ Standard say I should be able to compare two default-constructed STL iterators for equality? Are default-constructed iterators equality-comparable?

I want the following, using std::list for example:

void foo(const std::list<int>::iterator iter) {
    if (iter == std::list<int>::iterator()) {
        // Something
    }
}

std::list<int>::iterator i;
foo(i);

What I want here is something like a NULL value for iterators, but I'm not sure if it's legal. In the STL implementation included with Visual Studio 2008, they include assertions in std::list's operator==() that preclude this usage. (They check that each iterator is "owned" by the same container and default-constructed iterators have no container.) This would hint that it's not legal, or perhaps that they're being over-zealous.

Adrian
  • 1,842
  • 13
  • 25

4 Answers4

16

OK, I'll take a stab. The C++ Standard, Section 24.1/5:

Iterators can also have singular values that are not associated with any container. [Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. ] Results of most expressions are undefined for singular values; the only excep- tion is an assignment of a non-singular value to an iterator that holds a singular value.

So, no, they can't be compared.

13

This is going to change in C++14. [forward.iterators] 24.2.5p2 of N3936 says

However, value-initialized iterators may be compared and shall compare equal to other value-initialized iterators of the same type.

Hyman Rosen
  • 657
  • 4
  • 7
  • I hit this right now when implementing something at work :( I was wishing I had c++2014 but just have visual studio 2012 :D – Germán Diago Sep 30 '14 at 09:32
  • This is still not a good idea even in C++14 because non-singular iterators can't be compared against a value-initialized iterator. – T.C. Oct 07 '14 at 17:59
  • No, this does not really change anyting. Just because you can compare two value-initialized iterators does not mean that you can compare a value-initialized iterator with some other iterator. You can't. In the latter case the behavior is still undefined even after C++14. – AnT stands with Russia May 16 '19 at 17:29
1

I believe you should pass a range to the function.

void fun(std::list<int>::iterator beg, std::list<int>::iterator end)
{
    while(beg != end)
    {
        // do what you want here.
        beg++;
    }
}
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • 1
    Possibly true, but doesn't answer the question. –  Jul 27 '09 at 19:31
  • 1
    I understand what you're saying, but the semantics really call for a single item -- much like std::list::erase(). I may be abusing the concept of an iterator; that's what I'm interested in discovering. – Adrian Jul 27 '09 at 19:34
  • AraK, by what means can you have have a "null" iterator to pass in? – Andy J Buchanan Jul 27 '09 at 23:04
  • @Andy, I didn't understand your question. – Khaled Alshaya Jul 27 '09 at 23:09
  • The point is that range-function has the same problem - and gives a good reason for allowing the comparison in C++14. You can default-construct 'beg' and 'end' in the calling routine (and then possibly set them to an actual range) and call 'fun'. That requires the same test between two default-constructed iterators 'beg' and 'end'. (You cannot assume that the calling routine always has access to an appropriate container.) – Hans Olsson Jan 12 '17 at 14:22
1

Specification says that the postcondition of default constructor is that iterator is singular. The comparison for equality are undefined, so it may be different in some implementation.

Arpegius
  • 5,817
  • 38
  • 53