3

As of GCC 4.9.2, it's now possible to compile C++11 code that inserts or erases container elements via a const_iterator.

I can see how it makes sense for insert to accept a const_iterator, but I'm struggling to understand why it makes sense to allow erasure via a const_iterator.

This issue has been discussed previously, but I haven't seen an explanation of the rationale behind the change in behaviour.

The best answer I can think of is that the purpose of the change was to make the behaviour of const_iterator analogous to that of a const T*.

Clearly a major reason for allowing delete with const T* is to enable declarations such as:

const T* x = new T;
....
delete x;

However, it also permits the following less desirable behaviour:

int** x = new int*[2];
x[0] = new int[2];
const int* y = x[0];
delete[] y; // deletes x[0] via a pointer-to-const

and I'm struggling to see why it's a good thing for const_iterator to emulate this behaviour.

Community
  • 1
  • 1
j_h
  • 103
  • 1
  • 7
  • 7
    *but I haven't seen an explanation of the rationale behind the change in behaviour* yet, in the SO question you link to: *The iterator is only used to indicate a position in the (modifiable) container, and neither in case of insert or erase is the "pointee" of the iterator modified (in case of erase it just conceptually goes out of existence, which is a normal thing to do for const objects).* – stijn Jun 17 '15 at 19:55
  • 1
    Basically, if you have a non-const reference to the container, there's no reason to care about the const-ness of the iterator – Tavian Barnes Jun 17 '15 at 19:55
  • 1
    Did you read this: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf? – NathanOliver Jun 17 '15 at 20:01
  • @stijn I did read that point in the original post, but it seems to be a weak argument to say that going out of existence is a "normal thing to do". The purpose of a const_iterator is to allow access the elements of a container without modifying them. In the case of insert, the existing elements are not modified. In contrast, I would consider erasing to be a particularly severe form of modification. – j_h Jun 17 '15 at 20:05
  • 4
    @j_h: But you aren't using the iterator to modify the object, you're using the collection itself to modify the collection, and you are required to have a non-const lvalue for the collection. – Ben Voigt Jun 17 '15 at 20:08
  • @NathanOliver very informative link, thanks! – j_h Jun 17 '15 at 20:19

2 Answers2

8

erase and insert are non-const member functions of the collection. Non-const member functions are the right way to expose mutating operations.

The constness of the arguments are irrelevant; they aren't being used to modify anything. The collection can be modified because the collection is non-const (held in the hidden this argument).

Compare:

template <typename T>
std::vector<T>::iterator std::vector<T>::erase( std::vector<T>::const_iterator pos );
                                                                ^^^^^ ok

to a similar overload that is NOT allowed

template <typename T>
std::vector<T>::iterator std::vector<T>::erase( std::vector<T>::iterator pos ) const;
                                                                         wrong ^^^^^
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This is exactly the kind of explanation I was looking for! I think the key point is that erase is being called by the non-const container. If the const_iterator itself had a member function that permitted erasing the container elements, then this would be more of an issue. – j_h Jun 17 '15 at 20:17
  • 1
    @j_h: Called on, not by. The container is effectively a second argument to `erase`. – Ben Voigt Jun 17 '15 at 20:17
0
  1. The first question here is whether constness of an iterator is supposed to imply constnes of the entire container or just constness of the elements being iterated over.

    Apparently, it has been decided that the latter is the right approach. Constness of an iterator does not imply constness of the container, it only implies constness of container's elements.

  2. Since the beginning of times, construction of an object and its symmetrical counterpart - destruction of an object - were considered meta-operations with regards to the object itself. The object has always been supposed to behave as mutable with regard to these operations, even if it was declared as const. This is the reason you can legally modify const objects in their constructors and destructors. This is the reason you can delete an object of type T through a const T * pointer.

Given the resolution referred to by 1, it becomes clear that 2 should be extended to iterators as well.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765