c++c++11iteratorsetconst-iterator

Assigning a const_iterator to an iterator


I have the below snippet of code (which you can run here: http://coliru.stacked-crooked.com/a/2f62134b5c125051)

#include <iostream>
#include <set>
#include <map>

int main() 
{
    std::set<std::pair<const int, const int>> const mySet{{0,0}}; // value_type = std::pair<const int, const int>
    for (std::set<std::pair<const int, const int>>::iterator it  = mySet.cbegin(); it != mySet.cend(); ++it)
    {
        std::cout<<"set it = " << it->first << " " << it->second << std::endl;
    }

    std::map<const int, const int> const myMap{{0,0}}; // value_type = std::pair<const int, const int>
    for (std::map<const int, const int>::iterator it  = myMap.cbegin(); it != myMap.cend(); ++it)
    {
        std::cout<<"map it = " << it->first << " " << it->second << std::endl;
    }   
}

Can someone please explain me why for std::set the below does not throw any error:

std::set<std::pair<const int, const int>>::iterator it  = mySet.cbegin();

while for std::map the below throws error (no known conversion from _Rb_tree_const_iterator<std::pair<const int, const int> > to _Rb_tree_iterator<std::pair<const int, const int> >) as expected:

std::map<const int, const int>::iterator it  = myMap.cbegin();

How does it work for std::set? Shouldn't assigning a const_iterator to an iterator always throw an error?


Solution

  • You cannot modify a sets elements. Keys must be const to ensure the invariant promised by the set: elements are sorted and unique. A maps elements are sorted too, but you can modify the mapped value of the elements (keys are const as well). Elements of a std::map<A,B> are std::pair<const A,B>.

    On cppreference you can read that member aliases for iterators of std::set are

    iterator Constant LegacyBidirectionalIterator

    const_iterator Constant LegacyBidirectionalIterator

    They are both const iterators.

    On the other hand for a std::map they are:

    iterator LegacyBidirectionalIterator

    const_iterator Constant LegacyBidirectionalIterator

    Assigning a const_iterator to a non-const one is wrong. Its like trying to cast const away by assigning a pointer to const to a pointer to non-const. It won't work because you cannot make something that cannot be modified modifiable. That would break const-correctness.