4

As per this question, and assuming I have a mutable reference to the container itself, the constness of an iterator can be safely removed using:

foo::const_iterator cit = ... ;
foo::iterator it = c.erase( cit, cit );

However, this doesn't seem to work for forward_list's equivalent, erase_after, as per this code::

#include <iostream>
#include <forward_list>

typedef std::forward_list<int>::const_iterator CIT;
typedef std::forward_list<int>::iterator IT;

int main()
{
    std::forward_list<int> m{1, 2, 3};

    CIT cit = m.begin();
    IT it = m.erase_after(cit, cit); // Segmentation fault!

    std::cout << *it;
}

So is there any way to remove the constness of a const iterator for this class? Preferably not by iteration!

c z
  • 7,726
  • 3
  • 46
  • 59
  • related: [Why const_iterator does not provide a base like reverse_iterator?](https://stackoverflow.com/questions/33411326/why-const-iterator-does-not-provide-a-base-like-reverse-iterator) – underscore_d Sep 03 '20 at 14:47

3 Answers3

5

You have a segmentation fault because you're violating the precondition of erase_after(), which states that the range (first, last) passed to

iterator erase_after(const_iterator first, const_iterator last);

should be a valid range. Note that this is ()-type of range, not [), so both ends are excluded. That's why (cit, cit) is not a valid range for erase_after.

GCC with -D_GLIBCXX_DEBUG complains:

Error: function requires a valid iterator range (__pos, __last), __pos shall be before and not equal to __last.

Evg
  • 25,259
  • 5
  • 41
  • 83
2

although I think it's tricky and STL should provide a normal way to do that, there is also a solution by insert_after, because:

iterator insert_after(const_iterator position, size_type n, const T& x);

Preconditions: position is before_­begin() or is a dereferenceable iterator in the range [begin(), end()).

Effects: Inserts n copies of x after position.

Returns: An iterator pointing to the last inserted copy of x or position if n == 0.

it returns pos itself, if n == 0.

if you don't want to create a temporary object of T, you can use:

template<class InputIterator>
  iterator insert_after(const_iterator position, InputIterator first, InputIterator last);

or

iterator insert_after(const_iterator position, initializer_list<T> il);

and provide an empty sequence or initializer list.

RedFog
  • 1,005
  • 4
  • 10
  • 1
    @Evg he just want to convert `const_iterator` to `iterator`, why must be `erase_after`? and in fact no way by `erase_after`. – RedFog Sep 04 '20 at 02:15
-2

By iteration you can do it like:

IT it (m.begin());
for ( CIT cit = m.begin(); cit != m.end(); ++cit )
{
   std::advance (it, std::distance<CIT>(it, cit ) );
   // do changes on it
}
muaz
  • 550
  • 9
  • 15