Search code examples
c++stliteratorcontainersconst-iterator

Why const_iterator does not provide a base like reverse_iterator?


Why does const_iterator not provide a const_iterator::base() function, to obtain corresponding non-const iterator like reverse_iterator does?

Considering following pseudocode (say, geometric algorithm):

std::container< point > universe;
auto it = std::cbegin(universe);
std::list< decltype(it) > interesting_subset = sieve(it, std::cend(universe));
auto structure = algorithm(interesting_subset);

where universe is all the input points. After sieve()-ing the interesting_subset contains iterators to subset of universe's members. Following algorithm() constructs a resulting structure from interesting_subset, which consists of references (iterators) to members of the universe.

At the end, I want to change the points, containing into resulting structure (say, shift them). But equally I want to protect them from modyfining during algorithm action, and therefore I used std::cbegin/std::cend as opposite to std::begin/std::end. Finally I have only const_iterator references to source points.

This is a very use case for iterator std::container< T >::const_iterator::base() const member function I want to be present into STL containers.


Solution

  • Why does const_iterator not provide a const_iterator::base() function, to obtain corresponding non-const iterator like reverse_iterator does?

    To maintain const-safety. Providing such function would be very dangerous as already discussed here at length.

    At the end, I want to change the points, containing into resulting structure (say, shift them). But equally I want to protect them from modyfining during algorithm action, and therefore I used std::cbegin/std::cend as opposite to std::begin/std::end. Finally I have only const_iterator references to source points.

    Well, you're asking for the wrong thing with the base-member. Sure it would solve your problem, but as said, it's just too dangerous. Let me rephrease a question for you:

    If I have a const_iterator to an object and non-const access to the container, how do I efficiently (in constant time) get an iterator to the referred object?

    Here's a fancy trick to do exactly that:

    template <typename Container, typename ConstIterator>
    typename Container::iterator remove_constness(Container& c, ConstIterator it)
    {
        return c.erase(it, it);
    }
    

    I don't take any credit for the trick. I found it from https://stackoverflow.com/a/10669041/2079303 and they credit Howard Hinnant and Jon Kalb

    As discussed in the comments of that answer, this trick works with all standard containers, but not necessarily with all possible standard-compliant third-party containers because they're not required to provide erase.

    Personally, I would prefer that standard containers had a non-const member function that would convert a given const_iterator to an iterator, but they don't, so you need to work around it.