-1

When std::set<>::iterator is uninitialized, it is not equal to any other iterator in the set, but it is equal to other uninitialized iterators.

Is this GCC-specific implementation? (Is the uninitialized iterator actually initialized to an invalid value?)

#include <stdio.h>
#include <iostream>
#include <set>
#include <vector>

int main()
{
    std::set<int> s;
    std::set<int>::reverse_iterator inv = s.rend();
    std::cout << (inv == s.rend()) << "\n";
    std::cout << (inv == s.rbegin()) << "\n";
    s.insert(5);
    std::cout << (inv == s.rend()) << "\n";
    std::cout << (inv == s.rbegin()) << "\n";
    // invalidate
    inv = std::set<int>::reverse_iterator();
    std::cout << (inv == s.rend()) << "\n";
    std::cout << (inv == s.rbegin()) << "\n";

    auto inv2 = std::set<int>::reverse_iterator();
    std::cout << (inv == inv2) << "!!!\n";

    return 0;
}

prints:

1
1
0
1
0
0
1!!!

Live example: https://onlinegdb.com/r1--46u_B

Bill Kotsias
  • 3,258
  • 6
  • 33
  • 60
  • Possible duplicate of [What is an iterator's default value?](https://stackoverflow.com/questions/3395180/what-is-an-iterators-default-value) – Algirdas Preidžius Oct 07 '19 at 13:59
  • Possible duplicate of [Is it well-defined to compare with a value-initialized iterator?](https://stackoverflow.com/questions/26241878/is-it-well-defined-to-compare-with-a-value-initialized-iterator) – walnut Oct 07 '19 at 14:04
  • See also questions linked in the potential duplicate. – walnut Oct 07 '19 at 14:04
  • Iterators in C++ are basically pointers, so two "uninitialized" pointers are null pointers, and two null pointers are always equal...? – ShockCoding Oct 07 '19 at 14:12
  • 3
    @ShockCoding _"iterators are basically pointers"_ No, iterators are iterators. Even if they were "like" pointers, an uninitialised pointer is not a null pointer. You cannot compare two uninitialised pointers without UB. And, since (again) iterators are not pointers, further rules apply (read the linked posts) – Lightness Races in Orbit Oct 07 '19 at 14:19
  • It's not clear to me whether you're not invoking UB (and whether this depends on the starndard: C11 vs C14 vs C17 etc). – Walter Oct 07 '19 at 14:19
  • I have seen both of these older posts and they are not duplicates of my message. If this is a GCC only feature, I would like to know. – Bill Kotsias Oct 07 '19 at 14:19
  • @ShockCoding iterators may have behaviors similar to pointers, but they *aren't* the same. – Mark Ransom Oct 07 '19 at 14:20
  • They may not be word-for-word the same as your question, but they do answer it, if you read them. – Lightness Races in Orbit Oct 07 '19 at 14:20
  • @BillKotsias *If this is a GCC only feature, I would like to know.* -- Are you sure you want to write non-portable and non-standard code? Just rely on the standard and not on (un-documented) compiler extensions! – Walter Oct 07 '19 at 14:21
  • @LightnessRacesinOrbit I repeat: the question is: Is this GCC-specific? I am NOT asking if this is UB (it is!) – Bill Kotsias Oct 07 '19 at 14:21
  • If you already know it's UB, why are you asking whether it's specific to your implementation and non-portable? – Lightness Races in Orbit Oct 07 '19 at 14:22
  • 1
    Remember that undefined behavior is completely unpredictable, it may even do something reasonable. But you can't rely on it. – Mark Ransom Oct 07 '19 at 14:23

2 Answers2

3

How come 2 uninitialized std::set::iterator are equal?

They are not uninitialised. They are value initialised. A value initialised iterator is singular: it does not point to any container.

Behaviour of reading an uninitialised value would be undefined, but that's not what you do in the program.

it is not equal to any other iterator in the set

Comparison between input iterators is only defined for iterators to the same range. A singular iterator does not point to same range as any non singular iterator, so the comparison is undefined.

but it is equal to other uninitialized iterators.

Two singular iterators always compare equal.

Is this a GCC-specific, non-portable implementation?

Comparing singular iterator to non singular is undefined. Undefined behaviour is generally "non-portable", even within the same compiler version (unless compiler specifies the behaviour in which case it is non-portable to other compilers).

Singular iterators in general are standard since C++14, for all forward iterators.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

the question is: Is this GCC-specific? I am NOT asking if this is UB (it is!)

UB is UB.

By definition, the result you see is potentially unique to that particular run of code on that particular day.

Even if no other implementation ever manifested this behaviour, that doesn't matter, because you can't even rely on it on yours.

Worse, by relying on it, you are breaking a contract, and other parts of your program can break as a result.

So:

Is this a GCC-specific, non-portable implementation?

Yes.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055