18

I have two iterators into a container, one const and one non-const. Is there an issue with comparing them to see if they both refer to the same object in the container? This is a general C++11 iterator question:

Can a const and non-const iterator be legitimately compared to see if they both refer to the same object, independent of the type of container (i.e., they are both iterators that are guaranteed to refer to objects in the same container or that container's end(), but one is const and the other is not)?

For example, consider the following code:

some_c++11_container container;

// Populate container
...

some_c++11_container::iterator iObject1=container.begin();
some_c++11_container::const_iterator ciObject2=container.cbegin();

// Some operations that move iObject1 and ciObject2 around the container
...

if (ciObject2==iObject1) // Is this comparison allowed by the C++11 standard?
  ...; //Perform some action contingent on the equality of the two iterators
Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • Sure its valid. But note that you are comparing iterators, not the value pointed by the iterators. – dchhetri Jun 03 '13 at 15:44
  • 1
    @user814628 Evidence please? – BoBTFish Jun 03 '13 at 15:44
  • I thought this was obvious. If we can compare non-const to const object there is no reason we shouldn't be able to do iterators comparisons. – dchhetri Jun 03 '13 at 15:53
  • 4
    `some_container::iterator` and `some_container::const_iterator` might be different types. While they model `T *` and `T const *` that isn't what they actually are. That's why this is a good question. You would have a hard time finding an example that doesn't work, but that doesn't mean The Standard guarantees it will work. Well, except that now a couple of answers show that it does, but it is not what I would consider obvious/trivial. – BoBTFish Jun 03 '13 at 15:55
  • Do you know that both iterators refer to elements in the same container? That's not immediately clear from the question, since you elided the initialization in your example. – Adrian McCarthy Jun 04 '13 at 17:11
  • @Adrian, I've update the example to be more clear on this point. – Michael Goldshteyn Jun 04 '13 at 18:18

4 Answers4

14

Yes, this will work like you expect.

The Standard guarantees that for any container type, some_container::iterator can be implicitly converted to some_container::const_iterator.

The first table in 23.2.1 [container.requirements.general], after defining X as a container type which contains objects of type T, has:

Expression: X::iterator

Return type: iterator type whose value type is T

Note: any iterator category that meets the forward iterator requirements. convertible to X::const_iterator.


Expression: X::const_iterator

Return type: constant iterator type whose value type is T

Note: any iterator category that meets the forward iterator requirements.

(These aren't really expressions, and are types, rather than having "return types", but that's how they're squeezed into the table that is mostly expressions.)

So when you have ciObject2==iObject1, the compiler notices that the best operator== is ciObject2==some_container::const_iterator(iObject1). And operator== on two const_iterator tells you if they refer to the same element.

(I don't see anything explicitly saying that the result of this conversion refers to the same object as the original iterator. I guess that's just understood.)

Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • 1
    If you can quote chapter and verse, I'll consider the question answered and give you the checkmark. – Michael Goldshteyn Jun 03 '13 at 15:58
  • 5
    Note that this is not a requirement on containers, but an interface specification for the containers defined in the standard. So it does not apply to **all** iterators, only to iterators that come from standard containers. For other sources of iterators (containers or otherwise), check your documentation. – Pete Becker Jun 03 '13 at 17:22
2

From §24.2.3/1

A class or pointer type X satisfies the requirements of an input iterator for the value type T if X satisfies the Iterator (24.2.2) and EqualityComparable (Table 17) requirements ...

Thus input iterators are required to be EqualityComparable.

All standard library container iterators must satisfy forward iterator requirements (§23.2.1 - Table 96). Since those requirements are a superset of input iterator requirements, it follows these iterators must satisfy the EqualityComparable concept.

Also, from §23.2.1 - Table 96, X::iterator is required to be convertible to X::const_iterator.

Adding the two together answers your question that it is indeed required by the standard that comparing a Container::const_iterator to a Container::iterator is well-defined (as long as both are valid iterators pointing to the same container).

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • I tried looking this up in C++20 draft N4713. All occurrences of "iterator is convertible to" only appear in notes, i.e. they are not binding. There are 2 findings: §26.2.6(6) on page 763 and §26.2.7(8) on page 772. – Thomas Weller Jan 23 '23 at 13:53
1

I don't think it is possible for there to be an issue comparing them. If you have a const iterator when you check for it being the end the iterator end() returns is not const.

aaronman
  • 18,343
  • 7
  • 63
  • 78
  • I noticed the return of `end()` is a trailing return type, will the auto preserve const – aaronman Jun 03 '13 at 15:45
  • The `Container::end()` member functions have 2 overloads, one returning a `const` iterator, and the other non-`const`. – Praetorian Jun 03 '13 at 15:45
  • 3
    I've always thought that cbegin() and cend() were added to help with automatic type deduction. For example: `auto ciObject=myContainer.cbegin(); // ciObject is a const iterator to object` – Michael Goldshteyn Jun 03 '13 at 15:47
1

IIRC iterator implicitly converts to const_iterator. And the result must point to the same position.

If so the mixed compare will do the conversion then compare the now compatible const_iterators.

Balog Pal
  • 16,195
  • 2
  • 23
  • 37