Topic: Defect Report: constness of iterator arguments to container member functions has unintended consequences
Author: Dave Abrahams <abrahams@mediaone.net>
Date: 1999/07/01 Raw View
Here's a simple and typical example problem which is currently very=20
difficult or impossible to solve without the change proposed below.
=A0
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.
The problem is that 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.
Proposed solution: all non-const iterator parameters to container member
functions should be changed (or overloaded) to accept const_iterator
parameters.
This change has already been widely tested in the SGI STL, for example.
In 21.3/6 change:
iterator insert(iterator p, charT c);
void insert(iterator p, size_type n, charT c);
template<class InputIterator>
void insert(iterator p, InputIterator first, InputIterator last);
basic_string& erase(size_type pos =3D 0, size_type n =3D npos);
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
to:
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);
basic_string& erase(size_type pos =3D 0, size_type n =3D npos);
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
and:
basic_string& replace(iterator i1, iterator i2, const basic_string&
str);
basic_string& replace(iterator i1, iterator i2, const charT* s,
size_type n);
basic_string& replace(iterator i1, iterator i2, const charT* s);
basic_string& replace(iterator i1, iterator i2,
size_type n, charT c);
template<class InputIterator>
basic_string& replace(iterator i1, iterator i2,
InputIterator j1, InputIterator j2);
to:
basic_string& replace(const_iterator i1, const_iterator i2, const
basic_string& str);
basic_string& replace(const_iterator i1, const_iterator i2, const
charT* s,
size_type n);
basic_string& replace(const_iterator i1, const_iterator i2, const
charT* s);
basic_string& replace(const_iterator i1, const_iterator i2,
size_type n, charT c);
template<class InputIterator>
basic_string& replace(const_iterator i1, const_iterator i2,
InputIterator j1, InputIterator j2);
in 21.3.5.4 change:
iterator insert(iterator p, charT c);
to:
iterator insert(const_iterator p, charT c);
and:
void insert(iterator p, size_type n, charT c);
to:
void insert(const_iterator p, size_type n, charT c);
and:
template<class InputIterator>
void insert(iterator p, InputIterator first, InputIterator last);
to:
template<class InputIterator>
void insert(const_iterator p, InputIterator first, InputIterator last=
);
in 21.3.5.5 change:
iterator erase(iterator p);
to:
iterator erase(const_iterator p);
and:
iterator erase(iterator first, iterator last);
to:
iterator erase(const_iterator first, const_iterator last);
in 21.3.5.6 change:
basic_string& replace(iterator i1, iterator i2, const basic_string& str=
);
to:
basic_string& replace(const_iterator i1, const_iterator i2, const
basic_string& str);
and:
basic_string&
replace(iterator i1, iterator i2, const charT* s, size_type n);
to:
basic_string&
replace(const_iterator i1, const_iterator i2, const charT* s, size_ty=
pe
n);
and:
basic_string& replace(iterator i1, iterator i2, const charT* s);
to:
basic_string& replace(const_iterator i1, const_iterator i2, const charT=
*
s);
and:
basic_string& replace(iterator i1, iterator i2, size_type n,
charT c);
to:
basic_string& replace(const_iterator i1, const_iterator i2, size_type n=
,
charT c);
and:
template<class InputIterator>
basic_string& replace(iterator i1, iterator i2,
InputIterator j1, InputIterator j2);
to:
template<class InputIterator>
basic_string& replace(const_iterator i1, const_iterator i2,
InputIterator j1, InputIterator j2);
in 23.1.1/9 change:
template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);
to:
template <class InputIterator> // such as insert()
rt fx1(const_iterator p, InputIterator f, InputIterator l);
and:
template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);
to:
template <class InputIterator> // such as replace()
rt fx3(const_iterator i1, const_iteraror i2, InputIterator f,
InputIterator l);
....
You get the idea. There are lots of changes. You can find all of the plac=
es
by grepping for:
[(,][ \t\n]*iterator=20
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/07/01 Raw View
Dave Abrahams wrote:
>
> 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.
>
> The problem is that 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.
I didn't had to think much to write the following:
template <class Sequence>
class warper {
Sequence sequ;
public:
typedef typename Sequence::value_type const value_type;
class iterator {
friend warper;
typename Sequence::iterator pos;
iterator (typename Sequence::iterator where);
public:
value_type& operator* () const { return *pos; }
iterator& operator++ ()
{ ++pos; return *this; }
};
iterator insert (iterator where, value_type& what)
{ return iterator (sequ.insert (where.pos, what)); }
};
--
Valentin Bonnard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/07/05 Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote in message
news:377B3D97.12FC@wanadoo.fr...
VB> Dave Abrahams wrote:
VB> >
VB> > Here's a simple and typical example problem which is currently very
VB> > difficult or impossible to solve without the change proposed below.
VB> >
VB> > Wrap a standard container C in a class W which allows clients to find
and
VB> > read (but not modify) a subrange of (C.begin(), C.end()]. The only
VB> > modification clients are allowed to make to elements in this subrange is
to
VB> > erase them from C through the use of a member function of W.
VB> >
VB> > The problem is that it is the constness of the container which should
VB> > control whether it can be modified through a member function such as
VB> > erase(), not the constness of the iterators. The iterators only serve to
VB> > give positioning information.
VB>
VB> I didn't had to think much to write the following:
VB>
VB> template <class Sequence>
VB> class warper {
VB> Sequence sequ;
VB> public:
VB> typedef typename Sequence::value_type const value_type;
VB>
VB> class iterator {
VB> friend warper;
VB> typename Sequence::iterator pos;
VB> iterator (typename Sequence::iterator where);
VB> public:
VB> value_type& operator* () const { return *pos; }
VB> iterator& operator++ ()
VB> { ++pos; return *this; }
VB> };
VB>
VB> iterator insert (iterator where, value_type& what)
VB> { return iterator (sequ.insert (where.pos, what)); }
VB> };
This seems backwards. A client of warper (I assume your implemention of
wrapper class W in the problem statement) can only insert. The problem
desires the client to be able to read and remove (basically everything but
insert).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/07/07 Raw View
Ed Brey wrote:
EB>
BE> Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote in message
EB> VB> I didn't had to think much to write the following:
EB> VB>
EB> VB> template <class Sequence>
EB> VB> class warper {
EB> VB> Sequence sequ;
EB> VB> public:
EB> VB> typedef typename Sequence::value_type const value_type;
...
EB> VB> iterator insert (iterator where, value_type& what)
EB> VB> { return iterator (sequ.insert (where.pos, what)); }
EB> VB> };
EB>
EB> This seems backwards.
Perhaps
> A client of warper (I assume your implemention of
> wrapper class W in the problem statement) can only insert.
Yes
> The problem
> desires the client to be able to read and remove (basically everything but
> insert).
That's the ``dual'' problem, which is perfectely
equivalent.
--
Valentin Bonnard
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]