Search code examples
c++iteratorsetmultiset

Why is iterator in set(c++) not behaving properly?


This is code I have written:

multiset<int>S;
for(int i = 0;i<20;i++)
S.insert(i);
for(auto it = S.end();it!=S.begin();--it)
cout<<*it<<" ";
cout<<endl;

Output:

20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 

Solution

  • Your code contains some undefined behavior. As you already indicated S will contain all values from 0 till 20 (exclusive), though somehow the printing gives 1 til 20 (inclusive).

    Your code:

    for(auto it = S.end();it!=S.begin();--it)
        cout<<*it<<" ";
    

    The problem here is that the range [begin, end) has end referring to something which ain't part of the set. Dereferencing the iterator received from end() can crash your program or let it produce some random value. In this case, I guess you get the value 20 because of compiler optimizations. (Some black box optimization)

    In C++ (and other languages), the concept of iterators is accompanied by a concept of reverse iterators. (If you follow the link, there is a nice picture explaining the iterators.)

    Basically, using the reverse iterators will allow you to loop from the back to the beginning as if you were looping with normal iterators:

    for (auto it = S.crbegin(); it != S.crend(); ++it)
         cout << *it << " ";
    

    Note that the rbegin() and crbegin() don't have any disadvantages for code complexity. (unless you want to transform them to a forward iterator again)

    Bonus: By default, don't use the -- operator on iterators, it gives headaches when trying to debug.