Topic: Copying singular iterators


Author: dave@boost-consulting.com (David Abrahams)
Date: Tue, 20 Mar 2007 04:01:34 GMT
Raw View
on Mon Mar 19 2007, brangdon-AT-ntlworld.com (Dave Harris) wrote:

> kuyper@wizard.net () wrote (abridged):
>> > ... you can't replace iterators with pointers because
>> > the containers don't work with pointers. (Eg there is no efficient
>> > way to convert a pointer into an iterator that you can pass to
>> > std::list.)
>>
>> I'm confused by that assertion.  I've come up with three possible ways
>> that you might mean that statement, but none of them work:
>
> Your second way is closest. The context was Pete saying (as I understood
> him; I may have misunderstood) that people who needed a NULL-like value
> for iterators should use pointers instead. I'm saying that's sometimes
> impractical. You can have a pointer which is either NULL or the address of
> an object in a container, but you can't pass such a pointer to a container
> member function such as erase.

Nor can you use it to get to neighboring elements of the container, as
you would with an iterator.  I'm not sure every iterator type can
efficiently support a NULL state, but as a practical matter, I think
most could.  Having often wanted it myself, I know that
NullableIterator would be a useful concept.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Tue, 20 Mar 2007 14:47:41 CST
Raw View
David Abrahams wrote:
> on Mon Mar 19 2007, brangdon-AT-ntlworld.com (Dave Harris) wrote:
.
> > Your second way is closest. The context was Pete saying (as I understood
> > him; I may have misunderstood) that people who needed a NULL-like value
> > for iterators should use pointers instead. I'm saying that's sometimes
> > impractical. You can have a pointer which is either NULL or the address of
> > an object in a container, but you can't pass such a pointer to a container
> > member function such as erase.
>
> Nor can you use it to get to neighboring elements of the container, as
> you would with an iterator.  I'm not sure every iterator type can

When Pete said "Applications that need pointer semantics should use
pointers.", this implied that if such applications  need the ability
to get to neighboring elements, then those elements should be stored
in ways that ensure contiguity of the elements. The elements could be
stored in a array of T, std::valarray<T>, or std::vector<T>. I don't
remember whether the wording change that clearly ensures contiguity of
std::vector<T> was approved but I believe that it was.

Obviously, this seriously limits such applications, which is an
argument against Pete's assertion.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Sat, 17 Mar 2007 12:42:23 CST
Raw View
Dave Harris wrote:
.
> ... you can't replace iterators with pointers because
> the containers don't work with pointers. (Eg there is no efficient way to
> convert a pointer into an iterator that you can pass to std::list.)

I'm confused by that assertion.  I've come up with three possible ways
that you might mean that statement, but none of them work:

1) It's perfectly feasible to store a T* in a std::list<T*>, so that
can't be what you're referring to.

2) Many std::list<T> member functions take arguments which must have
the type std::list<T>::iterator or std::list<T>::const_iterator.
There's no way to convert a T* into either of those iterator types.
However, that's not specific to pointers, it's just as true of most
other kinds of iterators: there's no way to convert a
std::vector<T>::iterator into a std::list<T>::iterator, either.

3) Three of the std::list<T> functions take arbitrary InputIterators
as arguments. However, T* meets all of the requirements of an
InputIterator. In fact, T* meets all of the pointer requirements.
Those requriements were deliberately designed to allow pointers to
qualify. Therefore, the following code is perfectly legal:

int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::list<int> int_list(array, array+2);
int_list.assign(array+2, array+5);
int_list.insert(int_list.end(), array+5, array+10);

I've obviously misunderstood your point - could you explain it in a
bit more detail?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@ntlworld.com (Dave Harris)
Date: Mon, 19 Mar 2007 15:28:58 CST
Raw View
kuyper@wizard.net () wrote (abridged):
> > ... you can't replace iterators with pointers because
> > the containers don't work with pointers. (Eg there is no efficient
> > way to convert a pointer into an iterator that you can pass to
> > std::list.)
>
> I'm confused by that assertion.  I've come up with three possible ways
> that you might mean that statement, but none of them work:

Your second way is closest. The context was Pete saying (as I understood
him; I may have misunderstood) that people who needed a NULL-like value
for iterators should use pointers instead. I'm saying that's sometimes
impractical. You can have a pointer which is either NULL or the address of
an object in a container, but you can't pass such a pointer to a container
member function such as erase.

It's also true that you can't use a vector iterator when a list iterator
is expected, but that isn't relevant to the thread.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@ntlworld.com (Dave Harris)
Date: Thu, 15 Mar 2007 17:50:21 GMT
Raw View
mhilferink@objectvision.nl (MathGis) wrote (abridged):
> in my code I have been indicating empty ranges of T with default
> constructed vector<T>::iterators and I was disappointed when moving to
> VC8 (iterator debug mode) to find that the standard indeed prohibits
> this. I still wonder why.

I think the main issue is what should happen when you compare such
iterators. Currently you are not supposed to compare iterators from
different containers. If default constructed iterators are supposed to act
like NULL pointers, then they should be comparable to any iterator of the
same type. Would you expect these asserts to pass?

    std::vector<int> v1;
    std::vector<int> v2;
    std::vector<int>::iterator i();

    assert( i != v1.begin() );
    assert( i != v1.end() );
    assert( v1.begin() != v2.begin() );

    v1.push_back( 0 );
    assert( i != v1.begin() );
    assert( i != v1.end() );
    assert( v1.begin() != v2.begin() );

With some implementations, the first block would fail and the second block
pass, because vector::begin() can return a NULL pointer if its reserve is
0.

I think it would be reasonable to say that a default-constructed iterator
must not compare equal to any dereferenceable iterator, and must compare
equal to other default constructed iterators of the same type, with other
cases implementation-defined.

This would allow implementations to use default-constructed iterators for
end(), but not for begin() unless begin() == end(). I don't think that
would place onerous new restrictions on the implementation, but you can
see it is getting a bit scary; you have to try to guess what future
implementations and containers might want to do.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@ntlworld.com (Dave Harris)
Date: Thu, 15 Mar 2007 17:52:23 GMT
Raw View
pete@versatilecoding.com (Pete Becker) wrote (abridged):
> I haven't seen a convincing case for it. All the suggestions I've seen
> for having such a thing have come from misunderstanding how STL is
> designed. Iterators aren't pointers, and they don't need to act like
> them. Applications that need pointer semantics should use pointers.

If you want pointer semantics and you are also using standard containers,
this incompatibility between the two can create a problem. You can't
replace pointers with iterators because iterators have no way of
representing NULL, and you can't replace iterators with pointers because
the containers don't work with pointers. (Eg there is no efficient way to
convert a pointer into an iterator that you can pass to std::list.)

However, it is not wrong to want to use NULL, nor is it wrong to want to
use standard containers. I don't see why it should be a design error to
want both at the same time. It's just a limitation of the STL.

Most of the time you can just use c.end(), but that's not always
convenient because it needs access to the container. One workaround is to
use a pair<bool,iterator> where the bool is set to false to represent
NULL. Another workaround is to create a container especially, eg:

    struct ContainerView {
        typedef std::list<int> Container;
        typedef Container::iterator iterator;
        Container *c;
        static Container ifNone;

        iterator begin() {
            return c ? c->begin() : ifNone.begin();
        }
        iterator end() {
            return c ? c->end() : ifNone.end();
        }
        // ...
    };

where if c is NULL we want begin/end to return an empty sequence.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "MathGis" <mhilferink@objectvision.nl>
Date: Wed, 7 Mar 2007 08:52:27 CST
Raw View
On Mar 7, 5:11 am, a...@acm.org ("Andrew Koenig") wrote:
> "Sylvain Pion" <Sylvain.P...@sophia.inria.fr> wrote in message
>
> news:esje06$r76$1@news-sop.inria.fr...
>
> > I am wondering why there is such a strict requirement on singular values
> > of iterators.  Iterators are meant to be small pointer-like objects,
> > and I can't see any useful reason to disallow copies/assignments of
> > singular values (which would of course propagate the "singular-ness").
>
> One reason is that copying an uninitialized pointer is undefined:
>
>     int* p;
>     int* q = p;        // undefined behavior
>
> So the requirement on singular iterator values is necessary in order to
> allow pointers to be iterators.
>

However, I think the following code is legal:

  typedef int* int_ptr;
  int_ptr p = int_ptr(); // default ctor on 'built-in-type' assignes
NULL
  assert(p == NULL); // p has the 'singular' value for int_ptr
  int_ptr q = p; // the 'singular' value is copied. (q is copy
constructed)
  q = p;  // now the value of p is also assigned to q (redundant, for
demonstration purposes only)
  for (; p != q; ++p) // NULL can be compared, but should not be
incremented
     do_something(*p); // this line should only be called with non-
singluar int_ptr values

so, why shouldn't the following be legal?

  list<int>::iterator p = list<int>::iterator(); // use default ctor
to assign the singular value
  list<int>::iterator q = p; // the 'singular' value is copied. (q is
copy constructed)
  q = p;  // now the value of p is also assigned to q (redundant, for
demonstration purposes only)
  for (; p != q; ++p) // compare two singular values
     do_something(*p); // this line should only be called with non-
singluar iterator values

in my code I have been indicating empty ranges of T with default
constructed vector<T>::iterators and I was disappointed when moving to
VC8 (iterator debug mode) to find that the standard indeed prohibits
this. I still wonder why.

Maarten Hilferink
Object Vision
Netherlands

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sylvain.Pion@sophia.inria.fr (Sylvain Pion)
Date: Wed, 7 Mar 2007 17:31:12 GMT
Raw View
kuyper@wizard.net a =E9crit :
> People have a tendency to assume that a singular value for an iterator
> corresponds to a null value for a pointer. What it really corresponds
> to is an uninitialized value. Consider the following code:
>=20
> int *p;
>=20
> At this point, the value of 'p' is uninitialized. The only operations
> that can legally be performed on it are precisely the same operations
> that are permitted for singular iterators. In particular, consider a
> simple copy assignment:
>=20
> int *q =3D p;

Thank you both for the rationale behind this specification.

Now I guess, what is missing from the iterators concept is the
equivalent of NULL.

BTW, is the following undefined?

   typedef int* intptr;
   intptr p =3D intptr();
   intptr q =3D p;

And if OK, is this guaranteed to be null?

--=20
Sylvain

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: pete@versatilecoding.com (Pete Becker)
Date: Wed, 7 Mar 2007 17:58:46 GMT
Raw View
Sylvain Pion wrote:
>
> Now I guess, what is missing from the iterators concept is the
> equivalent of NULL.
>

Nope, not missing. Iterators aren't just pointers in fancy dress.
They're used in pairs, to designate ranges of elements. Idiomatic STL
(as in Standard Template Library, not C++ STandard Library) doesn't need
a distinguished value for an iterator that points nowhere.

--

 -- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Thu, 8 Mar 2007 08:15:43 CST
Raw View
On Mar 7, 6:31 pm, Sylvain.P...@sophia.inria.fr (Sylvain Pion) wrote:
> kuy...@wizard.net a    crit :
[...]
> Now I guess, what is missing from the iterators concept is the
> equivalent of NULL.

If you allow me a little digression, I was struck by this problem in a
rather unexpected way. A while ago I had to port a piece of code to a
newer release of the compiler we we're using. This new release
involved a change to a different implementation of the standard
library which used full fledged classes for vector iterators, rather
than pointers as did the previous library.

You can imagine my horror when I discovered that the code I was
working on actually used iterators as pointers, including assignment
of NULL to them! This was used to handle certain special cases, so I
could not directly get rid of it. In the end I substituted the
original iterators with boost::optional<vector<>::iterator > which
proved to be a reasonably convenient solution. The only drawback is
that the use of the dereference operator is not always consistent,
i.e. it's easy to get confused between checking for validity and
dereferencing.

Cheers,
Nicola Musatti


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 8 Mar 2007 11:52:57 CST
Raw View
MathGis wrote:
.
>   typedef int* int_ptr;
>   int_ptr p = int_ptr(); // default ctor on 'built-in-type' assignes
> NULL
>   assert(p == NULL); // p has the 'singular' value for int_ptr

p is zero-initialized, which means it contains a null pointer value.
What the standard says about singular iterator values doesn't match
what the standard says about null pointer values. You can copy null
pointer values, compare them for equality with other valid pointer
values. You can copy them and convert them to other pointer types, and
to integer types. The only thing you can safely do with a singular
iterator value is replace it with a non-singular value. The only
method specified in the standard for creating singular iterators is to
define an iterator without initializing it;  an uninitialized pointer
might represent a null pointer value, but that's not a reliable way of
creating them.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "slobasso" <slobasso@gmail.com>
Date: Thu, 8 Mar 2007 12:31:36 CST
Raw View
On Mar 6, 8:11 pm, a...@acm.org ("Andrew Koenig") wrote:
> "Sylvain Pion" <Sylvain.P...@sophia.inria.fr> wrote in message
>
> news:esje06$r76$1@news-sop.inria.fr...
>
> One reason is that copying an uninitialized pointer is undefined:
>
>     int* p;
>     int* q = p;        // undefined behavior
>
> So the requirement on singular iterator values is necessary in order to
> allow pointers to be iterators.

Could someone please point me to where in the standard this is
specified?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Thu, 8 Mar 2007 14:06:23 CST
Raw View
slobasso schrieb:

> On Mar 6, 8:11 pm, a...@acm.org ("Andrew Koenig") wrote:
> > "Sylvain Pion" <Sylvain.P...@sophia.inria.fr> wrote in message
> > One reason is that copying an uninitialized pointer is undefined:
> >
> >     int* p;
> >     int* q = p;        // undefined behavior
> >
> > So the requirement on singular iterator values is necessary in order to
> > allow pointers to be iterators.
>
> Could someone please point me to where in the standard this is
> specified?

1) 24.1/5:

"Iterators can also have singular values that are not associated with
any container. [Example: After the declaration of an uninitialized
pointer x (as with int* x;), x must always be assumed to have a
singular value of a pointer. ] Results of most expressions are
undefined
for singular values; the only exception is an assignment of a non-
singular
value to an iterator that holds a singular value. In this case the
singular
value is overwritten the same way as any other value. Dereferenceable
values are always nonsingular."

Related to that some other references:

2) 8.5/9:

"If no initializer is specified for an object,[..] Otherwise, if no
initializer is
specified for a nonstatic object, the object and its subobjects, if
any,
have an indeterminate initial value[..]"

3) Footnote 42:

"Using a bool value in ways described by this International Standard
as
''undefined,'' such as by examining the value of an uninitialized
automatic variable, might cause it to behave as if it is neither true
nor false."

4) 4.1 Lvalue-to-rvalue conversion:

"If the object to which the lvalue refers is not an object of type T
and is
not an object of a type derived from T, or if the object is
uninitialized, a
program that necessitates this conversion has undefined behavior."

Greetings from Bremen,

Daniel Kr   gler


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "slobasso" <slobasso@gmail.com>
Date: Thu, 8 Mar 2007 16:24:24 CST
Raw View
> > One reason is that copying an uninitialized pointer is undefined:
>
> >     int* p;
> >     int* q = p;        // undefined behavior

I'm sorry, I think I wasn't clear in my last question.
I know where the standard specifies this behavior for iterators.

Where is the above specified as undefined "behavior" for pointers? I
can understand it as an undefined "value".

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 8 Mar 2007 21:42:51 CST
Raw View
slobasso wrote:
> > > One reason is that copying an uninitialized pointer is undefined:
> >
> > >     int* p;
> > >     int* q = p;        // undefined behavior
>
> I'm sorry, I think I wasn't clear in my last question.
> I know where the standard specifies this behavior for iterators.
>
> Where is the above specified as undefined "behavior" for pointers? I
> can understand it as an undefined "value".

It's undefined behavior for any type, pointer or not:

4.1p1 (Lvalue to rvalue conversions): "If the object to which the
lvalue refers ... is uninitialized, a program that necessitates this
conversion has undefined behavior."

The assignment of the value of p to q necessitates that conversion.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 9 Mar 2007 15:05:09 GMT
Raw View
pete@versatilecoding.com (Pete Becker) wrote (abridged):
> Nope, not missing. Iterators aren't just pointers in fancy dress.
> They're used in pairs, to designate ranges of elements.

They are also used on their own. For example, std::vector::insert takes a
single iterator which says where the insertion should happen.


> Idiomatic STL (as in Standard Template Library, not C++ STandard
> Library) doesn't  need a distinguished value for an iterator that
> points nowhere.

True, but I've seen user code that wanted one.

And even the STL has one-past-the-end iterators which point to no object.
These are often usable, but they depend on a particular container. Given
the importance of NULL in the C++ memory model, it's a shame iterators
don't support it.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Fri, 9 Mar 2007 09:03:26 CST
Raw View
On Mar 9, 4:42 am, kuy...@wizard.net wrote:
> slobasso wrote:
> > > > One reason is that copying an uninitialized pointer is undefined:

> > > >     int* p;
> > > >     int* q = p;        // undefined behavior

> > I'm sorry, I think I wasn't clear in my last question.
> > I know where the standard specifies this behavior for iterators.

> > Where is the above specified as undefined "behavior" for pointers? I
> > can understand it as an undefined "value".

> It's undefined behavior for any type, pointer or not:

> 4.1p1 (Lvalue to rvalue conversions): "If the object to which the
> lvalue refers ... is uninitialized, a program that necessitates this
> conversion has undefined behavior."

With the exception of unsigned char (   3.9.1/1: "For unsigned
character types, all possible bit patterns of the value
representation represent numbers.").

(But the statement you quote should probably be corrected to
mention this exception.)

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: pete@versatilecoding.com (Pete Becker)
Date: Fri, 9 Mar 2007 15:51:13 GMT
Raw View
Dave Harris wrote:
> pete@versatilecoding.com (Pete Becker) wrote (abridged):
>> Nope, not missing. Iterators aren't just pointers in fancy dress.
>> They're used in pairs, to designate ranges of elements.
>
> They are also used on their own. For example, std::vector::insert takes a
> single iterator which says where the insertion should happen.
>

Yes, but that's an iterator that was obtained from a range, not one that
was made up on the spot. It's known to be valid, either pointing to an
element in the range or past the end, i.e. no element.

>
>> Idiomatic STL (as in Standard Template Library, not C++ STandard
>> Library) doesn't  need a distinguished value for an iterator that
>> points nowhere.
>
> True, but I've seen user code that wanted one.
>

That's a design problem in the user code.

> And even the STL has one-past-the-end iterators which point to no object.

Which is why I explicitly said "_a_ distinguished value" (emphasis
added). By design, STL does not have such a thing.

> These are often usable, but they depend on a particular container.

Not on a container, but on the sequence that they are applied to.
Containers are one way of creating sequences, but not the only one.

> Given
> the importance of NULL in the C++ memory model, it's a shame iterators
> don't support it.
>

I haven't seen a convincing case for it. All the suggestions I've seen
for having such a thing have come from misunderstanding how STL is
designed. Iterators aren't pointers, and they don't need to act like
them. Applications that need pointer semantics should use pointers.

--

 -- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: e0226430@stud3.tuwien.ac.at (Sebastian Redl)
Date: Fri, 9 Mar 2007 23:33:32 GMT
Raw View

On Thu, 8 Mar 2007, slobasso wrote:

> Where is the above specified as undefined "behavior" for pointers? I
> can understand it as an undefined "value".

4.1/1: "If the object to which the lvalue refers [...] is uninitialized, a
program that necessitates [the lvalue-to-rvalue] conversion has undefined
behavior."

4.1/2: "The value contained in the object indicated by the lvalue is the
rvalue result."

5.17/2: "In simple assignment (=), the value of the [right-hand]
expression replaces that of the object referred to by the left operand."

So, the left-hand side gets the value of the right-hand side. The value is
the rvalue result. Thus, lvalue-to-rvalue conversion takes place, which is
undefined behaviour for uninitialized variables of all kinds, not just
pointers. Thus, this too is undefined:

int i;
int j = i;

Sebastian Redl

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sylvain.Pion@sophia.inria.fr (Sylvain Pion)
Date: Tue, 6 Mar 2007 17:43:09 GMT
Raw View
Hi,

[24.1.5] states :
<< ... Results of most expressions are undefined for singular values;
the only exception is an assignment of a non-singular value to an
iterator that holds a singular value. ... >>

In practice, the debug mode of GCC's STL checks for this at run-time,
so that code like the following fails at run-time:

   std::list<int>::iterator it1, it2;
   it1 = it2;

Note that Visual C++'s debug mode does not seem to check for that.



I am wondering why there is such a strict requirement on singular values
of iterators.  Iterators are meant to be small pointer-like objects,
and I can't see any useful reason to disallow copies/assignments of
singular values (which would of course propagate the "singular-ness").
In practice, sometimes you want to store iterators, e.g. in containers,
or other places where you will do copies, and it is a pain to have to
take care of this issue for no visible gain.
So, does anybody know of any useful case for this requirement?

Otherwise, what about relaxing the constraints on iterators, and
modifying the sentence above from [24.1.5] to also allow
copy-construction and assignment?

--
Sylvain Pion
INRIA Sophia-Antipolis
Geometrica Project
CGAL, http://cgal.org/

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: ark@acm.org ("Andrew Koenig")
Date: Wed, 7 Mar 2007 04:11:12 GMT
Raw View
"Sylvain Pion" <Sylvain.Pion@sophia.inria.fr> wrote in message
news:esje06$r76$1@news-sop.inria.fr...

> I am wondering why there is such a strict requirement on singular values
> of iterators.  Iterators are meant to be small pointer-like objects,
> and I can't see any useful reason to disallow copies/assignments of
> singular values (which would of course propagate the "singular-ness").

One reason is that copying an uninitialized pointer is undefined:

    int* p;
    int* q = p;        // undefined behavior

So the requirement on singular iterator values is necessary in order to
allow pointers to be iterators.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Tue, 6 Mar 2007 22:11:14 CST
Raw View
Sylvain Pion wrote:
> Hi,
>
> [24.1.5] states :
> << ... Results of most expressions are undefined for singular values;
> the only exception is an assignment of a non-singular value to an
> iterator that holds a singular value. ... >>
>
> In practice, the debug mode of GCC's STL checks for this at run-time,
> so that code like the following fails at run-time:
>
>    std::list<int>::iterator it1, it2;
>    it1 = it2;
>
> Note that Visual C++'s debug mode does not seem to check for that.
>
>
>
> I am wondering why there is such a strict requirement on singular values
> of iterators.  Iterators are meant to be small pointer-like objects,
> and I can't see any useful reason to disallow copies/assignments of
> singular values (which would of course propagate the "singular-ness").
> In practice, sometimes you want to store iterators, e.g. in containers,
> or other places where you will do copies, and it is a pain to have to
> take care of this issue for no visible gain.

People have a tendency to assume that a singular value for an iterator
corresponds to a null value for a pointer. What it really corresponds
to is an uninitialized value. Consider the following code:

int *p;

At this point, the value of 'p' is uninitialized. The only operations
that can legally be performed on it are precisely the same operations
that are permitted for singular iterators. In particular, consider a
simple copy assignment:

int *q = p;

On many real platforms, the copy will be performed by loading it's
uninitialized value from memory into an address register, and then
writing the value of that register into the memory containing 'q'. On
many of those platforms, the load into the address register performs a
validity check on the address value, and if it's invalid, aborts your
program. This is a deliberate feature of those platforms, designed to
limit the amount of damage performed by code that is so poorly written
as to attempt to load invalid addresses into an address register. The
standard says that the behavior of such code is undefined, permitting
such implementations.

The standard extends this concept to singular iterators, permitting
pointers to qualify as iterators on such implementations. It also
permits implementation of iterators as user-defined types with similar
characteristics.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]