Topic: Must iterator::operator*() be const?


Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Wed, 18 Apr 2001 17:41:09 GMT
Raw View
On Tue, 17 Apr 2001 22:48:49 GMT, John Potter <jpotter@falcon.lhup.edu> wrote:
> On Mon, 16 Apr 2001 21:31:20 GMT, news/comp.std.c++@nmhq.net (Niklas
> Matthies) wrote:
>
> > On Mon, 16 Apr 2001 17:21:03 GMT, John Potter <jpotter@falcon.lhup.edu> wrote:
> > > On Sun, 15 Apr 2001 01:06:41 GMT, news/comp.std.c++@nmhq.net (Niklas
> > > Matthies) wrote:
> > >
> > > > I think one needs to differentiate. I agree that for output iterators
> > > > (and possibly input iterators) it makes sense for operator*() not to be
> > > > const.
> > >
> > > For output iterators, it makes no difference because *it is not valid.
> > > Only *it= is allowed.
> >
> > Well, `*it' is part of `*it='. Certainly `*it = val;' calls operator*()
> > for `it'.
>
> For the output iterators defined in the standard, *it returns it and
> the assignment is a member of the iterator.

The section describing the requirements on output iterators (24.1.2)
doesn't specify anything like this. There are no restrictions on the
return type of operator*() for output iterators other than it must be an
lvalue to which a certain other type is assignable to.

> Making operator* const would be a problem since it returns a non-const
> reference.  If it were overloaded, then the operator= would also need
> to be overloaded. Should *it = t be allowed for a const iterator?

Do you mean that question for all iterators, or only output iterators?
Anyway, since for example assigning to a container element through an
iterator via *it = t usually doesn't change the state of the iterator
(but only the state of the container), it would make very much sense for
the operator*() to be const in this case, and therefore it should be
allowed. And if it is allowed for random access iterators, it must
automatically be allowed for bidirectional, forward, input and output
iterators, since random access iterators are all of those.

> > > Input iterators have the same behavior as
> > > forward iterators in this discussion.
> >
> > Not necessarily, IMHO. Since input iterators are one-pass by design, I
> > don't really see the need to require them to be able to dereference more
> > than once between increments. For some applications, such a requirement
> > would mean for the iterator to internally cache the returned value (when
> > it can only retrieved once internally) in case it is requested again by
> > repeated dereferencing, and this caching could mean an unnecessary and
> > possibly unacceptable overhead for all algorithms that dereference the
> > iterator only once between increments (which are probably the majority
> > of algorithms that take an input iterator).
>
> Input iterators are one-pass in the sense that it is not possible to
> make a copy and dereference it after the original is advanced.  Merge
> is an example of an algorithm which will dereference its input iterators
> more than once without advancing.

It doesn't need to. Certainly for merge an lvalue needs to be cached,
but since this is a particularity of merge and not generally of one-pass
algorithms, it is more sensible to not make this a general requirement
on input iterators.

> > > It may fail to compile if *a is not comparable, but it must not break.
> >
> > I do not agree. According to the Standard, `a' being dereferenceable is
> > a pre-condition for *a, but not a post-condition. Hence:
>
> Since there is no post-condition, we may assume that nothing has
> changed and the pre-condition holds.

Is that so? That's not the classical meaning of post-conditions (or of
pre-conditions); but I see that the standard's definition of post-
condition can be interpreted that way. If so, then *it = t is not
allowed to have any observable behavior as well, since there is no
post-condition specified for this (for output iterators). This would
make output iterators pretty much useless.

-- Niklas Matthies

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de>
Date: Thu, 19 Apr 2001 17:23:11 GMT
Raw View
"Christopher Eltschka" <celtschk@dollywood.itp.tuwien.ac.at> schrieb:

> Output iterators _do_ actually change logically on assignment.

Ok, there are implementations ...

> A newly created output iterator is in "assignable state", that
> is, it is allowed to do *i =3D v, but not to do ++i. After you
> did the assignment, you may _not_ do another assignment, but
> only an increment. Therefore the iterator is oin anothre state,
> let's call it "advanceable state". Now you can increment it,
> and thus get it into assignable state again.
> Those two states are not explicit (there's no member you can
> check the current state, and generally the iterator doesn't
> actually differ between those states, often operator++ is even
> a no-op), but they are implicit in the definition what you may
> do with it.

... that work exactly like this. But they don't need to. There is
no reason, why all that has to be done in 'operator=3D', because
there is the requirement that after an assignment there has to be
an increment. And _I_ would expect all that 'state change stuff'
to happen in 'operator++' not 'operator=3D'.

Just to explain my initial question: I wanted to change the
behaviour of a given iterator class and therefore thought about
simply deriving from that class and overriding some functions.
Since I hadn't done this before and wanted to do it most generic,
I was wondering if there may be const versions of a particular
memberfunction or not. So my question wasn't really about what I
wanted to know, but I had given up deriving at all and found a
better solution ...

kind regards
=AB=20
--=20
PGP: 0x6F8F6E09 RSA/2048 E952 24D9 3096 F859 5CC8 BEBF 1D45 F357






---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Thu, 12 Apr 2001 21:30:17 GMT
Raw View
On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com> wrote:
> "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
> news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> > I am wondering if 'operator*' of an iterator has to be a
> > const member, or not. Looking through 'iterator requirements'
> > I could not find an answer. At first glance I would expect
> > the following to work with every kind of output iterator:
> >
> >     void func( iterator const& i, value_type v ) {
> >         *i = v;
> >     }
>
> As a matter of fact, it won't work.  Try it with any of the insert
> iterators or with an ostream_iterator.  All those implement operator* as a
> non-const member function.

Is there any particular reason for this? It seems like an arbitrary
restriction to me. One can always dereference const pointers (not
pointers-to-const), and iterators are supposed to be a generalization of
pointers, are they not?

-- Niklas Matthies

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrea Ferro" <AndreaF@UrkaDVD.it>
Date: Fri, 13 Apr 2001 09:05:06 GMT
Raw View
"Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
news:slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net...
> On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com>
wrote:
> > "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
> > news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> > > I am wondering if 'operator*' of an iterator has to be a
> > > const member, or not. Looking through 'iterator requirements'
> > > I could not find an answer. At first glance I would expect
> > > the following to work with every kind of output iterator:
> > >
> > >     void func( iterator const& i, value_type v ) {
> > >         *i = v;
> > >     }
> >
> > As a matter of fact, it won't work.  Try it with any of the insert
> > iterators or with an ostream_iterator.  All those implement operator* as a
> > non-const member function.
>
> Is there any particular reason for this? It seems like an arbitrary
> restriction to me. One can always dereference const pointers (not
> pointers-to-const), and iterators are supposed to be a generalization of
> pointers, are they not?

I do not see iterators as a generalization of pointers. There are many kind of
iterators. At most you could almost say that random iterators are a
generalization of pointers.

An iterator, in general, need not define any operators on it as constant.
Iterators are not classes. They are a sort of abstraction. There's no actual
requirement that an iterator has an operator*, therefore there cannot be a
requirement that it be const. An iterator must only enshure that a given set of
expressions is valid. Expression "*i=v" may not be valid for all iterators. It
is not for input iterators, for example. And you cannot use it twice with the
same iterator value if the iterator is an output iterator.

There's no requirement that "++i" changes the actual iterator value in memory,
it can be a no-op. The iterator value just changes logically. Also "*i=v" (not
for input iterators) may or may not change the itarator value in memory. In
either case you cannot write "*i=v1; *i=v2" for an output iterator. Even if the
implementation is such that the memory representation of the iteretor does not
change.

Both input and output iterators are for "single pass" algorithms. You do copy
such iterators when you pass them from function to function but you should never
consider more than one copy as "valid". And you generally do not pass iterators
by reference (not to say constant reference) for exactly that reason. Once you
say "f(i)" where f is a function and i is an iterator, you should no more use i
in any way, after the function returned. Unless you are shure that i is at least
a forward iterator. And this is true no matter what the function parameter is
unless you are shure that it is a non constant reference (no copy made) and that
the function itself does never make a copy of the iterator. Also if I is an
iterator type and i is of type I after you write "I j=i;" you can no more use i
if the iterator is output. You can if it is input, but "*i == *j" violates the
"no more than once for each logical value" and there's no no guarantee that "++i
== ++j".

--

Andrea Ferro

---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info http://www.brainbench.com/transcript.jsp?pid=2522556



---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Fri, 13 Apr 2001 10:45:23 GMT
Raw View
Niklas Matthies wrote:
>
> On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com> wrote:
> > "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
> > news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> > > I am wondering if 'operator*' of an iterator has to be a
> > > const member, or not. Looking through 'iterator requirements'
> > > I could not find an answer. At first glance I would expect
> > > the following to work with every kind of output iterator:
> > >
> > >     void func( iterator const& i, value_type v ) {
> > >         *i = v;
> > >     }
> >
> > As a matter of fact, it won't work.  Try it with any of the insert
> > iterators or with an ostream_iterator.  All those implement operator* as a
> > non-const member function.
>
> Is there any particular reason for this? It seems like an arbitrary
> restriction to me. One can always dereference const pointers (not
> pointers-to-const), and iterators are supposed to be a generalization of
> pointers, are they not?

I don't believe that operator*() is required to be be a const member,
but it also isn't prohibited from being one. While iterators are a
generalization of pointers, insert iterators and ostream_iterators are
special cases of iterators. Insert iterators must retain non-constant
state that describes where in the container they will insert. It's less
clear to me that ostream_iterators need to maintain non-const state; I'd
expect that the relevant state is stored in the ostream itself.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Fri, 13 Apr 2001 10:45:48 GMT
Raw View
In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
Matthies says...
>
>On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com> wrote:
>> "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
>> news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
>> > I am wondering if 'operator*' of an iterator has to be a
>> > const member, or not. Looking through 'iterator requirements'
>> > I could not find an answer. At first glance I would expect
>> > the following to work with every kind of output iterator:
>> >
>> >     void func( iterator const& i, value_type v ) {
>> >         *i = v;
>> >     }
>>
>> As a matter of fact, it won't work.  Try it with any of the insert
>> iterators or with an ostream_iterator.  All those implement operator* as a
>> non-const member function.
>
>Is there any particular reason for this? It seems like an arbitrary
>restriction to me. One can always dereference const pointers (not
>pointers-to-const), and iterators are supposed to be a generalization of
>pointers, are they not?
>
>-- Niklas Matthies

Iterators don't form a superset of pointers, because not everything
allowed on pointers is allowed on iterators. In particular, for
output iterators, only sequences of operator*(), operator++()
have to produce sensible output. If operator++() is a no-op,
operator*() can hold the entire functionality for the output
iterator. So this is a one reason to allow non-const operator*().

HTH,


--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.nl

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Fri, 13 Apr 2001 16:15:43 GMT
Raw View
Andrea Ferro wrote:
>
> "Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
> news:slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net...
...
> > pointers-to-const), and iterators are supposed to be a generalization of
> > pointers, are they not?
>
> I do not see iterators as a generalization of pointers. There are many kind of
> iterators. At most you could almost say that random iterators are a
> generalization of pointers.

And since random iterators are a specific kind of iterator, that means
that iterators in general are an even greater generalization of pointers
than random iterators are.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Sat, 14 Apr 2001 12:31:31 GMT
Raw View
On Fri, 13 Apr 2001 10:45:23 GMT, "James Kuyper Jr." <kuyper@wizard.net>
wrote:

> I don't believe that operator*() is required to be be a const member,
> but it also isn't prohibited from being one. While iterators are a
> generalization of pointers, insert iterators and ostream_iterators are
> special cases of iterators. Insert iterators must retain non-constant
> state that describes where in the container they will insert. It's less
> clear to me that ostream_iterators need to maintain non-const state; I'd
> expect that the relevant state is stored in the ostream itself.

For output iterators, operator* may not be used other than in *it=.  It
is a no-op.  There is no reason for the operator to be other than const.
Insert iterators are output iterators and operator* will not affect
their state.

The original question was about *it=.  I would not expect operator=
to be a const member for any iterator; however, the operator= in that
expression is a strange one.  Does the iterator change because the
ostream changes?  See the original question.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Sun, 15 Apr 2001 01:06:22 GMT
Raw View
Michiel Salters wrote:
>
> In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> Matthies says...
...
> Iterators don't form a superset of pointers, because not everything
> allowed on pointers is allowed on iterators. In particular, for

Can you specify any operation allowed on pointers that is prohibited on
iterators? You've given an example of something that is allowed on
pointers that is not guaranteed to work for output iterators, but not
being guaranteed is very different from being prohibited. For any
arbitrary type T, T* meets all of the iterator requirements for any of
the iterator types - that's no accident; it was a deliberate choice when
establishing those requirements.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Sun, 15 Apr 2001 01:06:31 GMT
Raw View
Niklas Matthies wrote:
>
> On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com> wrote:
> > "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
> > news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> > > I am wondering if 'operator*' of an iterator has to be a
> > > const member, or not. Looking through 'iterator requirements'
> > > I could not find an answer. At first glance I would expect
> > > the following to work with every kind of output iterator:
> > >
> > >     void func( iterator const& i, value_type v ) {
> > >         *i = v;
> > >     }
> >
> > As a matter of fact, it won't work.  Try it with any of the insert
> > iterators or with an ostream_iterator.  All those implement operator* as a
> > non-const member function.
>
> Is there any particular reason for this? It seems like an arbitrary
> restriction to me. One can always dereference const pointers (not
> pointers-to-const), and iterators are supposed to be a generalization of
> pointers, are they not?

Output iterators _do_ actually change logically on assignment.
A newly created output iterator is in "assignable state", that
is, it is allowed to do *i = v, but not to do ++i. After you
did the assignment, you may _not_ do another assignment, but
only an increment. Therefore the iterator is oin anothre state,
let's call it "advanceable state". Now you can increment it,
and thus get it into assignable state again.
Those two states are not explicit (there's no member you can
check the current state, and generally the iterator doesn't
actually differ between those states, often operator++ is even
a no-op), but they are implicit in the definition what you may
do with it.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Sun, 15 Apr 2001 01:06:41 GMT
Raw View
On Fri, 13 Apr 2001 10:45:48 GMT, Michiel Salters <Michiel.Salters@cmg.nl> wrote:
> In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> Matthies says...
> >
> >On Mon,  5 Mar 2001 21:34:35 GMT, Gillmer J. Derge <spam@gillmerderge.com> wrote:
> >> "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
> >> news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> >> > I am wondering if 'operator*' of an iterator has to be a
> >> > const member, or not. Looking through 'iterator requirements'
> >> > I could not find an answer. At first glance I would expect
> >> > the following to work with every kind of output iterator:
> >> >
> >> >     void func( iterator const& i, value_type v ) {
> >> >         *i = v;
> >> >     }
> >>
> >> As a matter of fact, it won't work.  Try it with any of the insert
> >> iterators or with an ostream_iterator.  All those implement operator* as a
> >> non-const member function.
> >
> >Is there any particular reason for this? It seems like an arbitrary
> >restriction to me. One can always dereference const pointers (not
> >pointers-to-const), and iterators are supposed to be a generalization of
> >pointers, are they not?
>
> Iterators don't form a superset of pointers, because not everything
> allowed on pointers is allowed on iterators.

Well, I agree that this argument was flawed.

> In particular, for output iterators, only sequences of operator*(),
> operator++() have to produce sensible output. If operator++() is a
> no-op, operator*() can hold the entire functionality for the output
> iterator. So this is a one reason to allow non-const operator*().

I think one needs to differentiate. I agree that for output iterators
(and possibly input iterators) it makes sense for operator*() not to be
const. But for forward iterators I would expect a guarantee that
application of operator*() does not change the state of the iterator,
that it remains dereferenceable and dereferencing results in the same
value; i.e. that for example in

   if (*a == *b) { std::assert(*a == *b); }

where a and b at the beginning are dereferenceable forward iterators,
the behaviour is defined and the assertion never breaks.

Or, for example

   SomeSequenceContainer<int> x, y;
   SomeSequenceContainer<int>::iterator a, b;
   ...
   for (a = x.begin(), b = y.begin();
        a != x.end() && b != y.end(); ++a, ++b)
   {
      *a = *b - *a;
   }

should work as expected for every container whose iterator is a forward
iterator (i.e. the two `*a' should be valid and reference the same
object). Otherwise, one would always need to be extra careful and write
something like:

   for (a = x.begin(), b = y.begin();
        a != x.end() && b != y.end(); ++a, ++b)
   {
      int& a_elem = *a;
      a_elem = *b - a_elem;
   }

Although the standard doesn't give such a guarantee, I think it would be
a very reasonable one. And given such a guarantee, it would likewise
make sense to guarantee that operator*() is const, since it doesn't
change the (appearant) state of the iterator.

Of course, I might have overlooked a compelling reason why such
guarantees should not be given, hence my original posting; but so far
I haven't seen any.

-- Niklas Matthies

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrea Ferro" <AndreaF@UrkaDVD.it>
Date: Sun, 15 Apr 2001 01:07:03 GMT
Raw View
"James Kuyper Jr." <kuyper@wizard.net> wrote in message
news:3AD6EE79.BDC97611@wizard.net...
> Andrea Ferro wrote:
> >
> > "Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
> > news:slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net...
> ...
> > > pointers-to-const), and iterators are supposed to be a generalization of
> > > pointers, are they not?
> >
> > I do not see iterators as a generalization of pointers. There are many kind
of
> > iterators. At most you could almost say that random iterators are a
> > generalization of pointers.
>
> And since random iterators are a specific kind of iterator, that means
> that iterators in general are an even greater generalization of pointers
> than random iterators are.

It really is a question of what you mean with generalization.
IMO if A is a generalization of B then A can do anything B can do, and more.
Therefore an generic iterator is not a generalization of a pointer, eventualy a
pointer is more general than an iterator.

A pointer can be used as an iterator, but iterators cannot be used as pointers.

--

Andrea Ferro

---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info http://www.brainbench.com/transcript.jsp?pid=2522556



---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Sun, 15 Apr 2001 01:07:32 GMT
Raw View
On Fri, 13 Apr 2001 10:45:48 GMT, Michiel
Salters<Michiel.Salters@cmg.nl> wrote:

> Iterators don't form a superset of pointers, because not everything
> allowed on pointers is allowed on iterators. In particular, for
> output iterators, only sequences of operator*(), operator++()
> have to produce sensible output.

For an output iterator, operator* is meaningless.  Only *it= has
any meaning.

> If operator++() is a no-op,
> operator*() can hold the entire functionality for the output
> iterator. So this is a one reason to allow non-const operator*().

Operator* is a no-op.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrea Ferro" <AndreaF@UrkaDVD.it>
Date: Sun, 15 Apr 2001 02:36:25 GMT
Raw View
"Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
news:slrn9de51d.c00.news/comp.std.c++@nightrunner.nmhq.net...
> On Fri, 13 Apr 2001 10:45:48 GMT, Michiel Salters <Michiel.Salters@cmg.nl>
wrote:
> > In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> > Matthies says...
....
> a very reasonable one. And given such a guarantee, it would likewise
> make sense to guarantee that operator*() is const, since it doesn't
> change the (appearant) state of the iterator.
>
> Of course, I might have overlooked a compelling reason why such
> guarantees should not be given, hence my original posting; but so far
> I haven't seen any.

IMO the most compelling reason is the definition of iterator itself.

Nothing in the standard say that if "I" is an iterator type, "const I" is also
an iterator type.

In other words you never ever want to apply a const modifier to an iterator. If
you do you are not guaranteed that the result is again an iterator at all.
Therefore an iterator class can implement "*i" for "i" of some iterator class in
any way it wishes.

--

Andrea Ferro

---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info http://www.brainbench.com/transcript.jsp?pid=2522556



---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrea Ferro" <AndreaF@UrkaDVD.it>
Date: Sun, 15 Apr 2001 09:00:18 GMT
Raw View
"James Kuyper Jr." <kuyper@wizard.net> wrote in message
news:3AD6F03C.8044AF2F@wizard.net...
> Michiel Salters wrote:
> >
> > In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> > Matthies says...
> ...
> > Iterators don't form a superset of pointers, because not everything
> > allowed on pointers is allowed on iterators. In particular, for
>
> Can you specify any operation allowed on pointers that is prohibited on
> iterators?

Nothing is prohibited on iterators because iterators are not classes. For an
iterator you have a set of things that are guaranteed, all the rest is not
specifyed. What Niklas was trying to point out is that there are things
guaranteed to work on pointers that are not guaranteed to work on iterators (not
even random iterators). Therefore it is incorrect to say that iterators are a
superset of pointers (iterators do not support all pointer semantics). It is
correct, however, to say that a pointer satisfyes all iterator requirements.

--

Andrea Ferro

---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info http://www.brainbench.com/transcript.jsp?pid=2522556



---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Sun, 15 Apr 2001 14:03:36 GMT
Raw View
Andrea Ferro wrote:
...
> Nothing in the standard say that if "I" is an iterator type, "const I" is also
> an iterator type.

In fact, the prototypical iterator "T*" violates many of the iterator
requirements if made const: ++, +=, --, -=, and = all fail in that case.
"T*const" doesn't meet the requirements for ANY iterator type.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Sun, 15 Apr 2001 14:04:05 GMT
Raw View
Andrea Ferro wrote:
>
> "James Kuyper Jr." <kuyper@wizard.net> wrote in message
> news:3AD6F03C.8044AF2F@wizard.net...
> > Michiel Salters wrote:
> > >
> > > In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> > > Matthies says...
> > ...
> > > Iterators don't form a superset of pointers, because not everything
> > > allowed on pointers is allowed on iterators. In particular, for
> >
> > Can you specify any operation allowed on pointers that is prohibited on
> > iterators?
>
> Nothing is prohibited on iterators because iterators are not classes. For an

Neither are pointers; they're both type categories. I don't see the
relevance of that fact.

> iterator you have a set of things that are guaranteed, all the rest is not
> specifyed. What Niklas was trying to point out is that there are things
> guaranteed to work on pointers that are not guaranteed to work on iterators (not
> even random iterators). ...

Agreed - that make pointers a subset of iterators. They're the
particular subset which meets those additional requirements.

> ... Therefore it is incorrect to say that iterators are a
> superset of pointers (iterators do not support all pointer semantics). It is

There are iterator types that satisfy all pointer semantics - they're
called 'pointers'. There are other iterator types which don't. That's
why iterator types is a type category that is a superset of the pointer
type category.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Sun, 15 Apr 2001 21:20:26 GMT
Raw View
On Sun, 15 Apr 2001 01:06:31 GMT, Christopher Eltschka
<celtschk@dollywood.itp.tuwien.ac.at> wrote:

> Output iterators _do_ actually change logically on assignment.
> A newly created output iterator is in "assignable state", that
> is, it is allowed to do *i = v, but not to do ++i. After you
> did the assignment, you may _not_ do another assignment, but
> only an increment. Therefore the iterator is oin anothre state,
> let's call it "advanceable state". Now you can increment it,
> and thus get it into assignable state again.
> Those two states are not explicit (there's no member you can
> check the current state, and generally the iterator doesn't
> actually differ between those states, often operator++ is even
> a no-op), but they are implicit in the definition what you may
> do with it.

This is all true of an algorithm which claims to support an output
iterator.  It must start with assignment and alternate assignment
and increment.  None of it is in the requirements of an output
iterator.  It is the total lack of requirements for output iterator
which places these restrictions on algorithms.

For the five output iterators defined in the standard, it is required
that it=t is equivalent to *it++=t.  There is no such requirement
for the output iterator concept.

Every forward iterator is-a output iterator in spite of the fact that
forward_iterator_tag is-not-a output_iterator_tag.  A forward iterator
may be used in any algorithm that supports an output iterator.

A constant iterator (const_iterator) is-not-a output iterator.

A const iterator (T* const) is not a constant iterator (T const*).

What does any of this have to do with operator* being const?  Given
that iterators are a generalization of pointers (24.1/1), it seems
that *it=t would be allowed for a const iterator in the same way that
it is for a T*const.  The standard says little about const_iterator
and nothing about const iterator.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Mon, 16 Apr 2001 00:03:58 GMT
Raw View
On Sun, 15 Apr 2001 02:36:25 GMT, Andrea Ferro <AndreaF@UrkaDVD.it> wrote:
> "Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
> news:slrn9de51d.c00.news/comp.std.c++@nightrunner.nmhq.net...
> > On Fri, 13 Apr 2001 10:45:48 GMT, Michiel Salters <Michiel.Salters@cmg.nl> wrote:
> > > In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> > > Matthies says...
> ....
> > a very reasonable one. And given such a guarantee, it would likewise
> > make sense to guarantee that operator*() is const, since it doesn't
> > change the (appearant) state of the iterator.
> >
> > Of course, I might have overlooked a compelling reason why such
> > guarantees should not be given, hence my original posting; but so far
> > I haven't seen any.
>
> IMO the most compelling reason is the definition of iterator itself.
>
> Nothing in the standard say that if "I" is an iterator type, "const I"
> is also an iterator type.
>
> In other words you never ever want to apply a const modifier to an
> iterator. If you do you are not guaranteed that the result is again an
> iterator at all. Therefore an iterator class can implement "*i" for
> "i" of some iterator class in any way it wishes.

But why? I want to able to pass an iterator by reference to a function
and ensure that the function doesn't "move" it. Currently I'm prevented
from declaring a member function const if it accesses an iterator member
or to declare an iterator reference parameter const if conceptually the
function ought not to change the iterator's state. The most natural
example is a class that contains an iterator as a data member. There are
meaningful operations on a const instance of that class that require
dereferencing the iterator (or compare it with another iterator, or make
a copy of it, etc.), but which is not possible if you're not allowed to
have const iterators (or to dereference one). In some cases you can get
around this by having an additional class member that is a pointer to
the object referenced by the iterator (or a copy of the value returned
by dereferencing), but this unnecessarily consumes additional space and
time and requires this additional member to be kept in sync with the
iterator member. This looks just plain annoying to me.

It is perfectly clear that an iterator type declared as const, or being
implicitly const because it is part of a const object instance, doesn't
support all operations that the standard requires for a type to be
called an iterator type. But my point is exactly that there should be a
subset of these operations that should be guaranteed to still work with
const instances; and for forward iterators I think that this should
include operator*(). That the standard doesn't do this seems like an
oversight or a defect to me. Or is there a good reason why it would be
unwise to require such a guarantee?

-- Niklas Matthies

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Mon, 16 Apr 2001 17:21:31 GMT
Raw View
Andrea Ferro wrote:
>
> "James Kuyper Jr." <kuyper@wizard.net> wrote in message
> news:3AD6EE79.BDC97611@wizard.net...
> > Andrea Ferro wrote:
> > >
> > > "Niklas Matthies" <news/comp.std.c++@nmhq.net> wrote in message
> > > news:slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net...
> > ...
> > > > pointers-to-const), and iterators are supposed to be a generalization of
> > > > pointers, are they not?
> > >
> > > I do not see iterators as a generalization of pointers. There are many kind
> of
> > > iterators. At most you could almost say that random iterators are a
> > > generalization of pointers.
> >
> > And since random iterators are a specific kind of iterator, that means
> > that iterators in general are an even greater generalization of pointers
> > than random iterators are.
>
> It really is a question of what you mean with generalization.

I call a category G a generalization of a category S if everything which
meets the requirements for category S also meets the requirements for
category G. Thus, "tool" is a more general category than "screwdriver".

> IMO if A is a generalization of B then A can do anything B can do, and more.

I think that your definition can be interpreted to match my definition,
but you're clearly interpreting it in a way that is almost exactly the
reverse of my definition. The key thing is that you're saying "can do",
whereas what I think you really mean is "is guaranteed able to do". To
take my example above, I think that what you're saying corresponds to
claiming that "screwdriver" is more general than "tool" because a
screwdriver is guaranteed able to drive screws, while tools in general
aren't.

However, in terms of your actual wording, tools is more general than
screws. This is because tools can drive screws, since some tools are
screwdrivers, but tools can also tighten bolts, something that no
ordinary screwdriver can do, because some tools are wrenches. I had to
say "ordinary", because I'm sure someone out there has built a
combination wrench/screwdriver :-).  Similarly, iterators include
pointers, so iterators can do everything that pointers can do. In
addition, particular iterator types can do some things that no pointer
type can do. For example:

An iterator type can have an operator<() which returns 'double'. A
pointer type can't.

An iterator type can have an operator--() which does the same thing that
operator++() does. A pointer type can't.

An iterator type can have an Assigneable
std::iterator_traits<ITERATOR>::value_type, while also having an
operator*() which returns a type for which operator=() does not return a
value. A pointer type can't.

> Therefore an generic iterator is not a generalization of a pointer, eventualy a
> pointer is more general than an iterator.
>
> A pointer can be used as an iterator, but iterators cannot be used as pointers.

Sure they can. Any iterator which happens to BE a pointer can certainly
be used as pointer.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 16 Apr 2001 17:21:03 GMT
Raw View
On Sun, 15 Apr 2001 01:06:41 GMT, news/comp.std.c++@nmhq.net (Niklas
Matthies) wrote:

> I think one needs to differentiate. I agree that for output iterators
> (and possibly input iterators) it makes sense for operator*() not to be
> const.

For output iterators, it makes no difference because *it is not valid.
Only *it= is allowed.  Input iterators have the same behavior as
forward iterators in this discussion.

> But for forward iterators I would expect a guarantee that
> application of operator*() does not change the state of the iterator,
> that it remains dereferenceable and dereferencing results in the same
> value; i.e. that for example in
>
>    if (*a == *b) { std::assert(*a == *b); }
>
> where a and b at the beginning are dereferenceable forward iterators,
> the behaviour is defined and the assertion never breaks.

It may fail to compile if *a is not comparable, but it must not break.

Input iterators are comparable and if a == b is true, the effect of
*a is equivalent to *b.  That wording is used to cover the case where
*a is not comparable.

If a == b, ++a may invalidate b.  Operator++ must change the iterator.
There is no requirement for algorithms to alternate increment and
dereference.

  cout << distance(istream_iterator<string>(cin),
        istream_iterator<string>()) << endl;

will count the whitespace delimeted words (wc -w).

Since the increment must change the iterator, the dereference may not.
There is no reason for operator* being other than const.

Forward iterators may be used where input iterators are specified and
the above applies to them as well for operator*.

For any iterator where the expression is valid, assert(*a == *a) must
not break.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 16 Apr 2001 17:22:30 GMT
Raw View
On Sun, 15 Apr 2001 14:03:36 GMT, "James Kuyper Jr." <kuyper@wizard.net>
wrote:

> In fact, the prototypical iterator "T*" violates many of the iterator
> requirements if made const: ++, +=, --, -=, and = all fail in that case.
> "T*const" doesn't meet the requirements for ANY iterator type.

Agreed, but so what?  The subject is operator*.  For T*const p:

   *p = t; assert(*p == t); assert(*p == *p);

will compile and pass if T is comparable.  The question is whether the
same is true for iterators and if not why.

template <class X> void silly (X const& x) {
    *x;
    }
int main () {
    silly(vector<int>(1).begin());       // pointer
    silly(deque<int>(1).begin());        // random_access
    silly(list<int>(1).begin());         // bidirectional
    silly(slist<int>(1).begin());        // forward, non-standard
    silly(istream_iterator<int>(cin));   // input
    silly(ostream_iterator<int>(cout));  // output
    *ostream_iterator<int>(cout);
    }

All but the output iterator pass on an implementation.  Does the
standard require it?  The fact that the error on the output iterator
is about operator* not being const is only strange, the statement is not
required for output iterators.  However, the non-const version passes.
But what's a real compiler to do with valid syntax not required by the
standard?  Placing = 42 in the two dereference statements only
changes the input iterator case.  Assignment to a dereferenced input
iterator is not required.

I think that there is support in the standard for the statement that
*it will not modify the iterator for any iterator.  A sequence of *it;
statements has no observable behavior.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Mon, 16 Apr 2001 21:31:20 GMT
Raw View
On Mon, 16 Apr 2001 17:21:03 GMT, John Potter <jpotter@falcon.lhup.edu> wrote:
> On Sun, 15 Apr 2001 01:06:41 GMT, news/comp.std.c++@nmhq.net (Niklas
> Matthies) wrote:
>
> > I think one needs to differentiate. I agree that for output iterators
> > (and possibly input iterators) it makes sense for operator*() not to be
> > const.
>
> For output iterators, it makes no difference because *it is not valid.
> Only *it= is allowed.

Well, `*it' is part of `*it='. Certainly `*it = val;' calls operator*()
for `it'.

> Input iterators have the same behavior as
> forward iterators in this discussion.

Not necessarily, IMHO. Since input iterators are one-pass by design, I
don't really see the need to require them to be able to dereference more
than once between increments. For some applications, such a requirement
would mean for the iterator to internally cache the returned value (when
it can only retrieved once internally) in case it is requested again by
repeated dereferencing, and this caching could mean an unnecessary and
possibly unacceptable overhead for all algorithms that dereference the
iterator only once between increments (which are probably the majority
of algorithms that take an input iterator).

> > But for forward iterators I would expect a guarantee that
> > application of operator*() does not change the state of the iterator,
> > that it remains dereferenceable and dereferencing results in the same
> > value; i.e. that for example in
> >
> >    if (*a == *b) { std::assert(*a == *b); }
> >
> > where a and b at the beginning are dereferenceable forward iterators,
> > the behaviour is defined and the assertion never breaks.
>
> It may fail to compile if *a is not comparable, but it must not break.

I do not agree. According to the Standard, `a' being dereferenceable is
a pre-condition for *a, but not a post-condition. Hence:

   // assume that a is dereferenceable at this point
   *a;  // required to work, but a may become non-dereferenceable
   *a;  // may cause undefined behavior if a is not dereferenceable any more

This is what I was getting at in the example quoted above. Actually,
looking at the Standard again, the situation is even worse:

   // assume that a is dereferenceable at this point
   *a;  // required to work, but a may become non-dereferenceable
   ++a; // may cause undefined behavior if a is not dereferenceable any
        // more, because dereferenceability is a precondition for ++a

> Since the increment must change the iterator, the dereference may not.

Well, that's probably what is intended, but the Standard doesn't state
such a requirement on dereferencing. I certainly agree that it should.

And for pretty much the same reason the Standard should require
not-value-changing operations of iterators (such as operator*() ought
to be one) to be const.

But currently the Standard doesn't guarantee neither.

-- Niklas Matthies

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Tue, 17 Apr 2001 01:32:30 GMT
Raw View
John Potter wrote:
>
> On Sun, 15 Apr 2001 14:03:36 GMT, "James Kuyper Jr." <kuyper@wizard.net>
> wrote:
>
> > In fact, the prototypical iterator "T*" violates many of the iterator
> > requirements if made const: ++, +=, --, -=, and = all fail in that case.
> > "T*const" doesn't meet the requirements for ANY iterator type.
>
> Agreed, but so what?  The subject is operator*.  For T*const p:

I was responding to one particular comment by Andrea Ferro, not making a
contribution to the main thread.

>    *p = t; assert(*p == t); assert(*p == *p);
>
> will compile and pass if T is comparable.  The question is whether the
> same is true for iterators and if not why.

It won't be true in general. Let's go down through the iterator types in
order:

Input iterator: *p isn't required to be Assignable.

Output iterator: *p isn't required to return a type that supports any
operation other than =t.

Forward iterator: EqualityComparable is not sufficient. First of all, T
must Mutable for *p=t to be valid. Secondly, T must be Assignable to
invoke the post-condition on = that *p is equivalent to t. For forward
iterators, == is supposed to define an equivalence relationship, so
p==p. Again, from the forward iterator requirements, p==p is supposed to
require that *p and *p are the same object. If T is EqualityComparable,
then that implies that *p == *p.

Bidirectional iterators, Random Access iterators: add nothing relevant
beyond what's implied by the fact that they're required to meet the

Thus, for forward iterators to Mutable, Assignable, EqualityComparable
types, the line you asked about will hold up. That means that *p cannot
change which object p points at. You don't even need EqualityComparable
to guarantee that it can't change which object p points at. However,
that falls short of requiring that operator*() be const. Granted, what
object an iterator points at is the defining characteristic of a
iterator, so prohibiting it from changing is close to requiring logical
constness. However, nothing prohibits an iterator in general from having
additional state, such as a count of how many times operator*() has been
called for it.

...
> I think that there is support in the standard for the statement that
> *it will not modify the iterator for any iterator.  A sequence of *it;
> statements has no observable behavior.

Can you indicate where that support lies?

The standard does not require *it to modify the iterator. It does not
guarantee that repeated applications of *it will have any observable
behavior. However, as far as I can tell, the standard says nothing to
prohibit *it from modifying the iterator. It says nothing to prohibit
repeated applications of *it from having observable behavior (such as
changing the value returned by a get_count() member function).

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Tue, 17 Apr 2001 13:13:25 GMT
Raw View
In article <3AD6F03C.8044AF2F@wizard.net>, James Kuyper Jr. says...
>
>Michiel Salters wrote:
>>
>> In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
>> Matthies says...
>...
>> Iterators don't form a superset of pointers, because not everything
>> allowed on pointers is allowed on iterators.

>Can you specify any operation allowed on pointers that is prohibited on
>iterators

Subscripting.

const char* pc ="Hello, world";
char c = pc[3];

Regards,

--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.nl

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Tue, 17 Apr 2001 22:48:49 GMT
Raw View
On Mon, 16 Apr 2001 21:31:20 GMT, news/comp.std.c++@nmhq.net (Niklas
Matthies) wrote:

> On Mon, 16 Apr 2001 17:21:03 GMT, John Potter <jpotter@falcon.lhup.edu> wrote:
> > On Sun, 15 Apr 2001 01:06:41 GMT, news/comp.std.c++@nmhq.net (Niklas
> > Matthies) wrote:
> >
> > > I think one needs to differentiate. I agree that for output iterators
> > > (and possibly input iterators) it makes sense for operator*() not to be
> > > const.
> >
> > For output iterators, it makes no difference because *it is not valid.
> > Only *it= is allowed.
>
> Well, `*it' is part of `*it='. Certainly `*it = val;' calls operator*()
> for `it'.

For the output iterators defined in the standard, *it returns it and
the assignment is a member of the iterator.  Making operator* const
would be a problem since it returns a non-const reference.  If it
were overloaded, then the operator= would also need to be overloaded.
Should *it = t be allowed for a const iterator?

> > Input iterators have the same behavior as
> > forward iterators in this discussion.
>
> Not necessarily, IMHO. Since input iterators are one-pass by design, I
> don't really see the need to require them to be able to dereference more
> than once between increments. For some applications, such a requirement
> would mean for the iterator to internally cache the returned value (when
> it can only retrieved once internally) in case it is requested again by
> repeated dereferencing, and this caching could mean an unnecessary and
> possibly unacceptable overhead for all algorithms that dereference the
> iterator only once between increments (which are probably the majority
> of algorithms that take an input iterator).

Input iterators are one-pass in the sense that it is not possible to
make a copy and dereference it after the original is advanced.  Merge
is an example of an algorithm which will dereference its input iterators
more than once without advancing.

> > It may fail to compile if *a is not comparable, but it must not break.
>
> I do not agree. According to the Standard, `a' being dereferenceable is
> a pre-condition for *a, but not a post-condition. Hence:

Since there is no post-condition, we may assume that nothing has
changed and the pre-condition holds.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Tue, 17 Apr 2001 22:58:33 GMT
Raw View
Michiel Salters wrote:
>
> In article <3AD6F03C.8044AF2F@wizard.net>, James Kuyper Jr. says...
> >
> >Michiel Salters wrote:
> >>
> >> In article <slrn9db5j8.646.news/comp.std.c++@nightrunner.nmhq.net>, Niklas
> >> Matthies says...
> >...
> >> Iterators don't form a superset of pointers, because not everything
> >> allowed on pointers is allowed on iterators.
>
> >Can you specify any operation allowed on pointers that is prohibited on
> >iterators
>
> Subscripting.

Is supported on random access iterators.

>
> const char* pc ="Hello, world";
> char c = pc[3];

std::string s = "Hello world";
char c = s.begin()[3];

This must be supported even if std::string::iterator is not a char*.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Tue, 17 Apr 2001 23:03:05 GMT
Raw View
Michiel Salters wrote:
>
> In article <3AD6F03C.8044AF2F@wizard.net>, James Kuyper Jr. says...
...
> >Can you specify any operation allowed on pointers that is prohibited on
> >iterators
>
> Subscripting.

Citation please? Where is this prohibited? In fact, according to table
76, random-access iterators are actually required to support
subscripting.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Tue, 17 Apr 2001 23:34:01 GMT
Raw View
"James Kuyper Jr." <kuyper@wizard.net> writes:

| Michiel Salters wrote:
| >
| > In article <3AD6F03C.8044AF2F@wizard.net>, James Kuyper Jr. says...
| ...
| > >Can you specify any operation allowed on pointers that is prohibited on
| > >iterators
| >
| > Subscripting.
|
| Citation please? Where is this prohibited? In fact, according to table
| 76, random-access iterators are actually required to support
| subscripting.

Maybe Michiel was referring to p[0] \equiv 0[p], something you can't
write with non-pointer random-access iterators.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Wed, 18 Apr 2001 01:56:36 GMT
Raw View
On Tue, 17 Apr 2001 01:32:30 GMT, "James Kuyper Jr." <kuyper@wizard.net>
wrote:

> John Potter wrote:

> >    *p = t; assert(*p == t); assert(*p == *p);
> >
> > will compile and pass if T is comparable.  The question is whether the
> > same is true for iterators and if not why.
>
> It won't be true in general. Let's go down through the iterator types in
> order:
>
> Input iterator: *p isn't required to be Assignable.

But, you have ignored the only real question.  If p is dereferencable
and *p is equality comparable, can assert(*p == *p) fail for an input
iterator?  For the two input iterators defined in the standard,
operator* is const.

> Thus, for forward iterators to Mutable, Assignable, EqualityComparable
> types, the line you asked about will hold up. That means that *p cannot
> change which object p points at. You don't even need EqualityComparable
> to guarantee that it can't change which object p points at. However,
> that falls short of requiring that operator*() be const. Granted, what
> object an iterator points at is the defining characteristic of a
> iterator, so prohibiting it from changing is close to requiring logical
> constness. However, nothing prohibits an iterator in general from having
> additional state, such as a count of how many times operator*() has been
> called for it.

As always, an interesting counter example, thanks.  Would that state be
considered in operator==?  Could assert(p == (*p, p)) fail?  If not, the
member should be mutable and operator* should still be const.

John

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de>
Date: Mon, 5 Mar 2001 19:55:09 GMT
Raw View
I am wondering if 'operator*' of an iterator has to be a
const member, or not. Looking through 'iterator requirements'
I could not find an answer. At first glance I would expect
the following to work with every kind of output iterator:

    void func( iterator const& i, value_type v ) {
        *i = v;
    }

TIA

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Gillmer J. Derge" <spam@gillmerderge.com>
Date: Mon, 5 Mar 2001 21:34:35 GMT
Raw View
"Markus Schaaf" <m.schaaf.exp-jun2001@gmx.de> wrote in message
news:97vnbs$qo9rd$1@ID-3706.news.dfncis.de...
> I am wondering if 'operator*' of an iterator has to be a
> const member, or not. Looking through 'iterator requirements'
> I could not find an answer. At first glance I would expect
> the following to work with every kind of output iterator:
>
>     void func( iterator const& i, value_type v ) {
>         *i = v;
>     }

As a matter of fact, it won't work.  Try it with any of the insert
iterators or with an ostream_iterator.  All those implement operator* as a
non-const member function.

-----
Gillmer J. Derge


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]