180. Container member iterator arguments constness has unintended consequences

Section: 24.3.2 [basic.string] Status: CD1 Submitter: Dave Abrahams Opened: 1999-07-01 Last modified: 2016-11-12

Priority: Not Prioritized

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with CD1 status.

Discussion:

It is the constness of the container which should control whether it can be modified through a member function such as erase(), not the constness of the iterators. The iterators only serve to give positioning information.

Here's a simple and typical example problem which is currently very difficult or impossible to solve without the change proposed below.

Wrap a standard container C in a class W which allows clients to find and read (but not modify) a subrange of (C.begin(), C.end()]. The only modification clients are allowed to make to elements in this subrange is to erase them from C through the use of a member function of W.

[ post Bellevue, Alisdair adds: ]

This issue was implemented by N2350 for everything but basic_string.

Note that the specific example in this issue (basic_string) is the one place we forgot to amend in N2350, so we might open this issue for that single container?

[ Sophia Antipolis: ]

This was a fix that was intended for all standard library containers, and has been done for other containers, but string was missed.

The wording updated.

We did not make the change in replace, because this change would affect the implementation because the string may be written into. This is an issue that should be taken up by concepts.

We note that the supplied wording addresses the initializer list provided in N2679.

Proposed resolution:

Update the following signature in the basic_string class template definition in 24.3.2 [basic.string], p5:

namespace std {
  template<class charT, class traits = char_traits<charT>,
    class Allocator = allocator<charT> >
  class basic_string {

    ...

    iterator insert(const_iterator p, charT c);
    void insert(const_iterator p, size_type n, charT c);
    template<class InputIterator>
      void insert(const_iterator p, InputIterator first, InputIterator last);
    void insert(const_iterator p, initializer_list<charT>);

    ...

    iterator erase(const_iterator const_position);
    iterator erase(const_iterator first, const_iterator last);

    ...

  };
}

Update the following signatures in 24.3.2.6.4 [string.insert]:

iterator insert(const_iterator p, charT c);
void insert(const_iterator p, size_type n, charT c);
template<class InputIterator>
  void insert(const_iterator p, InputIterator first, InputIterator last);
void insert(const_iterator p, initializer_list<charT>);

Update the following signatures in 24.3.2.6.5 [string.erase]:

iterator erase(const_iterator const_position);
iterator erase(const_iterator first, const_iterator last);

Rationale:

The issue was discussed at length. It was generally agreed that 1) There is no major technical argument against the change (although there is a minor argument that some obscure programs may break), and 2) Such a change would not break const correctness. The concerns about making the change were 1) it is user detectable (although only in boundary cases), 2) it changes a large number of signatures, and 3) it seems more of a design issue that an out-and-out defect.

The LWG believes that this issue should be considered as part of a general review of const issues for the next revision of the standard. Also see issue 200.