Topic: Questions about iterator library


Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/06/23
Raw View
bparker@gil.com.au (Brian Parker) writes:

|>  >(3) There's no mention of which operations are const.  I would expect
|>  >operator*() on an iterator to be const (it doesn't modify the iterator),
|>  >but the CD is silent on this point.
|>
|>  As long as an iterator fulfills the requirements, it shouldn't really
|>  matter how the functions are implemented.

But the const-ness of a function is part of the interface, not the
implementation.  Basically, what is being asked is, given:

 void f( SomeContainer::iterator const& i ) ;

what operations can f do on i?

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
            -- Conseils en informatique industrielle --
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: bparker@gil.com.au (Brian Parker)
Date: 1997/06/24
Raw View
On 23 Jun 97 11:07:12 GMT, James Kanze
<james-albert.kanze@vx.cit.alcatel.fr> wrote:

>bparker@gil.com.au (Brian Parker) writes:
>
>|>  >(3) There's no mention of which operations are const.  I would expect
>|>  >operator*() on an iterator to be const (it doesn't modify the iterator),
>|>  >but the CD is silent on this point.
>|>
>|>  As long as an iterator fulfills the requirements, it shouldn't really
>|>  matter how the functions are implemented.
>
>But the const-ness of a function is part of the interface, not the
>implementation.  Basically, what is being asked is, given:
>
> void f( SomeContainer::iterator const& i ) ;
>
>what operations can f do on i?

You're right- I suppose that constness should be specified.
It's not really an issue in the typical usage of iterators passed
by-value, but in a function such as f it would be. If the constness is
not specified in the standard then one would need to assume that the
iterator could be modified and hence only pass iterators by non-const
reference.

,Brian Parker (bparker@gil.com.au)

---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Kresimir Fresl <fresl@grad.hr>
Date: 1997/06/19
Raw View
Kevin S. Van Horn wrote:

> I've been reading through the Dec. '96 CD, and I'm finding a few
> things in the iterator library rather puzzling:
...
> (2) For random iterators, it says that it[n] only needs to have a
> type convertible to T, rather than T&.  This seems to imply that
> I can't count on
>   a[n] = E;
> being legal.
...

[Few weeks ago I asked similar question both in c.s.c++ and
c.l.c++.mod., but there was no reply. Maybe we'll be more
lucky now.]

Here are few more notes on that subject:

Aforementioned requirement is in section 24.1, table 7,
`Random access iterator requirements (in addition to
bidirectional iterator)`, column `return type'. Same table
states that the `operational semantics' of `a[n]' is
`*(a + n)'.

`*a' is not mentioned in table 7, but in table 5, `Forward
iterator requirements' [and table 6 is, of course,
`Bidirectional iterator requirements (in addition to forward
iterator)'].

And in table 5, `return value' of `*a' is defined as `T&',
and it is also said: `If X is mutable, *a = t is valid'.

Now, what the term `operational semantics' really means?
Is it that `observable behaviour should be the same'?
Or something else?

On the other hand, if we can't write `a[n] = E', what is
the rationale behind that? Isn't this too severe restriction?

BTW, in the original HP STL documentation and in the
Musser & Saini's book return type of `*a' is defined as
`convertible to T', but with the additional requirement
`If X is mutable, *a = t is valid'.


fres

email: fresl@grad.hr
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: bparker@gil.com.au (Brian Parker)
Date: 1997/06/20
Raw View
On 17 Jun 1997 09:28:11 PDT, "Kevin S. Van Horn"
<kevin.s.vanhorn@iname.com> wrote:

>I've been reading through the Dec. '96 CD, and I'm finding a few things in
>the iterator library rather puzzling:
>
>(1) The requirements for bidirectional iterators state that *it++ returns a
>value of type T& (T is the iterator's value type), but *it-- only needs to
>return a value convertible to T.  Why the assymetry?  This seems to say
>that
>  T& foo = *it--
>isn't guaranteed to be legal.
>
>(2) For random iterators, it says that it[n] only needs to have a type
>convertible to T, rather than T&.  This seems to imply that I can't count
>on
>  a[n] = E;
>being legal.
>
That's got to be a bug in the draft. The latest SGI version of the STL
(at www.sgi.com) specifies that for an iterator x, *x returns a type
convertible to T to allow for a proxy implementation, but also
specifies that for mutable iterators the dereference assignment
expression *x = t is defined (output iterators are an exception). The
draft's current wording seems to have a mix of over-specifying (i.e.
specifying a return type of T for input iterator *a where it should be
"a type convertible to T") and under-specifying in that it doesn't
state that *x = t is required for mutable types.

I don't know what is on the committee's agenda, but hopefully these
bugs will be fixed.

>(3) There's no mention of which operations are const.  I would expect
>operator*() on an iterator to be const (it doesn't modify the iterator),
>but the CD is silent on this point.
>

As long as an iterator fulfills the requirements, it shouldn't really
matter how the functions are implemented.

>(4) Why is the class forward_iterator_tag derived only from
>input_iterator_tag, and not also from output_iterator_tag?  I thought that
>forward iterators were supposed to satisfy all the requirements of both
>input iterators and output iterators (along with a few more of their own).

I suppose to avoid the overhead of multiple inheritance amongst other
reasons- the tags are only used for compile-time function selection so
they need to be light-weight. In any case, I don't know that the
inheritance of tags is actually needed or used in the STL.

>
>(5) For the istream_iterator class template, operator*() is listed as
>returning a value of type const T &.  But an istream_iterator is an input
>iterator, and earlier it states that operator*() for an input iterator
>should return a value of type T.  This is an important difference: if
>operator*() returns a value of type T, then
>  const T & x = *it; ++it;
>is a safe thing to do, where as if it returns a value of type const T &
>then the above is not safe, because the returned reference may be invalid
>after incrementing it.
>
>(6) The ctor for the ostream_iterator class takes a second argument "delim"
>of type const char *.  Does the iterator make its own copy of this char
>array?  Or is the caller required to leave this char array unmodified and
>undeleted for the lifetime of the ostream_iterator object constructed using
>it?  Does the iterator take over ownership of the char array (being
>responsible for deleting it upon destruction)?

Good question. Typically one just uses a string literal and so it
doesn't matter in that case, but I agree it should be specified.

,Brian Parker (bparker@gil.com.au)
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Kevin S. Van Horn" <kevin.s.vanhorn@iname.com>
Date: 1997/06/17
Raw View
I've been reading through the Dec. '96 CD, and I'm finding a few things in
the iterator library rather puzzling:

(1) The requirements for bidirectional iterators state that *it++ returns a
value of type T& (T is the iterator's value type), but *it-- only needs to
return a value convertible to T.  Why the assymetry?  This seems to say
that
  T& foo = *it--
isn't guaranteed to be legal.

(2) For random iterators, it says that it[n] only needs to have a type
convertible to T, rather than T&.  This seems to imply that I can't count
on
  a[n] = E;
being legal.

(3) There's no mention of which operations are const.  I would expect
operator*() on an iterator to be const (it doesn't modify the iterator),
but the CD is silent on this point.

(4) Why is the class forward_iterator_tag derived only from
input_iterator_tag, and not also from output_iterator_tag?  I thought that
forward iterators were supposed to satisfy all the requirements of both
input iterators and output iterators (along with a few more of their own).

(5) For the istream_iterator class template, operator*() is listed as
returning a value of type const T &.  But an istream_iterator is an input
iterator, and earlier it states that operator*() for an input iterator
should return a value of type T.  This is an important difference: if
operator*() returns a value of type T, then
  const T & x = *it; ++it;
is a safe thing to do, where as if it returns a value of type const T &
then the above is not safe, because the returned reference may be invalid
after incrementing it.

(6) The ctor for the ostream_iterator class takes a second argument "delim"
of type const char *.  Does the iterator make its own copy of this char
array?  Or is the caller required to leave this char array unmodified and
undeleted for the lifetime of the ostream_iterator object constructed using
it?  Does the iterator take over ownership of the char array (being
responsible for deleting it upon destruction)?

(7) The istreambuf_iterator proxy class seems more elaborate than necessary
for istreambuf_iterator to fulfill the requirements of an an input
iterator.  In particular, why is there a need to be able to construct an
istreambuf_iterator object from a proxy object?  As far as I can tell, the
requirements for an input iterator would be satisfied if the proxy object
was merely a wrapper for a charT value, with operator*() returning this
encapsulated value, and no conversion from a proxy object to an
istreambuf_iterator object allowed.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]