Topic: Why "!=" instead of "<" for iterators?


Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/07/27
Raw View
[Note to moderator: Hope this isn't off topic.  The issue has been put to
rest already.  But since I'm new to STL myself, I'm curious to know why
the STL iterators are designed the way they are.  My first instinct would
also have been to use "<" for comparing iterators, although a list
iterator I designed used a member function "notdone()" which is similar
to "!=" as it turns out to be much easier to implement. -- sbnaran].

>I think that it's only a programming style problem. May be the examples
>you read (as those present in my book) were wrtited with a compleate
>iteration on the container in mind.
>That's true: both of them work well, but only in that case. I learned at
>the university that it's better to use the standard idiom becouse it work
>in any case (since you can increment the controll variable by any value,
>and not only by one) and you never need to mind if the controll variable
>can jamp the control: i mean:


No one method works all the time.

for (int i=0; i!=9; i+=2) ;
// loops forever; one should use "<"

for (list::iterator i=l.begin(); i<l.end(); ++i) ;
// does "<" compare addresses
// if so, this loop might never kick off; one should use "!="


In a linked list, items aren't stored contiguously in memory.  So the
address of the last element may be less than the address of the first
element.  If this is the case, the condition in the for loop will be
false even before the first iteration of the loop.  So the loop will
never kick off; in other cases, only part of the loop may execute.


But we could design the iterator so that "<" works.  Just give the
iterator an integer index field.  So l.begin() returns an iterator
that points to the beginning of the list and has index=0.  And
l.end() returns an iterator that points to NULL of the list and has
index=N.  Now the "<" is well defined: it just compares the integer
index fields.

One immediate disadvantage of this method is that the size of the
iterator has increased by the inclusion of this index field.

But now what happens if you have many iterators iterating over the
same structure and you use one of the iterators to delete an item
or remove an item from the list?  For example, "a" points to the
1st element, "c" points to the 3rd element, "j" points to the
10th and last element.  If you use the iterator "a" to delete the
1st element in the list, then the iterators "c" and "j" are going
to be invalid (their index field will be invalid; for example, "c"
has index=3 whereas index=2 is correct).

We still could make this scheme work.  Just register each index
with the list.  That is, the list knows about each iterator that
points to it.  So when we update the list through one iterator, the
list updates all the iterators.  But there are numerous
disadvantages.

   Time penalty   --  because all the iterators must be checked and updated
   Space penalty  --  sizeof list is increased by knowledge of iterators
   Tight coupling --  list and iterator have to know a lot about each other
   Cyclic testing --  we can't test the list and iterator in isolation
   Extensibility? --  how to handle different types of iterators?
   Nightmare      --  this method is hard and ugly to program

Note that we can always create our own iterators by deriving from or
layering upon the basic STL iterators.  So the 'Extensibility?'
argument becomes even more prominent.  And as regards 'Nightmare'
note that code that is ugly to write is also ugly to maintain.




>By the way is your task to choose a style (i hope the best one) for your

We probably need different styles for different parts of the program.
If we're iterating through the element of a container one by one,
then the "!=" method is probably the best one because it works on
all containers.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@my-dejanews.com
Date: 1998/07/23
Raw View
In article <Pine.GSO.3.96.980722145712.2534B-100000@gilda.cs.unibo.it>,
  Luca De Vitis <devitis@CS.UniBO.IT> wrote:
> On 18 Jul 1998, Glen Perkins wrote:
>
> > Is the less than operator undefined or otherwise unusable for some of the
> > containers' iterators?
>
> I think that it's only a programming style problem. May be the examples
> you read (as those present in my book) were wrtited with a compleate
> iteration on the container in mind.
> That's true: both of them work well, but only in that case. I learned at
> the university that it's better to use the standard idiom becouse it work
> in any case (since you can increment the controll variable by any value,
> and not only by one) and you never need to mind if the controll variable
> can jamp the control:

You seem to have missed the point: operator<= or operator< is only defined
on random access iterators; containers (like list) with bidirectional
iterators or forward iterators don't define it, for the simple reason
that they cannot practically do so.  Of course, the problem you point
out with jumping an increment is real.  According to the standard,
incrementing beyond the end of the iterator is undefined behavior -- a
good implementation might cause an assertion failure, or a core dump.
A bad one might reformat your hard disk.  Writing code to use the standard
library can be very tricky; the interface (like much else in C/C++)
was designed for the few people who never make mistakes, and not
for the normal programmers like myself.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Luca De Vitis <devitis@CS.UniBO.IT>
Date: 1998/07/22
Raw View
On 18 Jul 1998, Glen Perkins wrote:

> Is the less than operator undefined or otherwise unusable for some of the
> containers' iterators?

I think that it's only a programming style problem. May be the examples
you read (as those present in my book) were wrtited with a compleate
iteration on the container in mind.
That's true: both of them work well, but only in that case. I learned at
the university that it's better to use the standard idiom becouse it work
in any case (since you can increment the controll variable by any value,
and not only by one) and you never need to mind if the controll variable
can jamp the control: i mean:

for (i = a; i != /* == */ b; i += /* i++ , ++i , --i ecc. */ c)

may not work; instead:

for (i = a; i < /* > , >= , <= */ b; i += /* i++ , ++i , --i ecc. */ c)

allways work.

i.e.

for (i = val; i != 7; i += 2) { // may work properly but depend on val!
// any code
}

for (i = val; i < 7; i += 2) { // allways wark properly
// any code
}

I tryed this on this section of code:

#include <vector.h>
#include <algo.h>
#include <iostream.h>
#include <iterator.h>

int main()
{
   vector<int>::iterator iter;
   vector<int> int_vec(9);
   int i;
   for (iter=int_vec.begin(), i=0; iter<=int_vec.end(); iter+=2, i++) {
      *iter = i;
      cout << *iter << "\n";
   }
   for (iter=int_vec.begin()+1, i=0; iter<int_vec.end(); iter+=2, i++) {
      *iter = i + 1;
      cout << *iter << "\n";
   }
   for (iter = int_vec.begin(); iter < int_vec.end(); iter++)
      cout << *iter;
   cout << "\n";
}

and it seems to work even if it seems it has no sense (infact i don't
remember i used an iteration like this one, but i see many in exams texts
;) ).

By the way is your task to choose a style (i hope the best one) for your
programs.

 I hope being right and answered yuor question

  Luca De Vitis

P.S. may be my english is not "perfect", excuse me ^_^





[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/07/22
Raw View
Luca De Vitis wrote:
>
> On 18 Jul 1998, Glen Perkins wrote:
>
> > Is the less than operator undefined or otherwise unusable for some of the
> > containers' iterators?
>
> I think that it's only a programming style problem. May be the examples
> you read (as those present in my book) were wrtited with a compleate
> iteration on the container in mind.

They were written with a complete iteration over an C array in mind. The
iterator for a C array is a T*, which is a random access iterator.

> That's true: both of them work well, but only in that case. I learned at
> the university that it's better to use the standard idiom becouse it work
> in any case (since you can increment the controll variable by any value,
> and not only by one) and you never need to mind if the controll variable
> can jamp the control: i mean:
>
> for (i = a; i != /* == */ b; i += /* i++ , ++i , --i ecc. */ c)
>
> may not work; instead:
>
> for (i = a; i < /* > , >= , <= */ b; i += /* i++ , ++i , --i ecc. */ c)
>
> allways work.
>
> i.e.
>
> for (i = val; i != 7; i += 2) { // may work properly but depend on val!
> // any code
> }
>
> for (i = val; i < 7; i += 2) { // allways wark properly
> // any code
> }

The corresponding code with iterators won't work with containers like
list<> which don't have random access iterators, because operator+=()
isn't defined for them.

> I tryed this on this section of code:
>
> #include <vector.h>
> #include <algo.h>
> #include <iostream.h>
> #include <iterator.h>
>
> int main()
> {
>    vector<int>::iterator iter;
>    vector<int> int_vec(9);
>    int i;
>    for (iter=int_vec.begin(), i=0; iter<=int_vec.end(); iter+=2, i++) {
>       *iter = i;
>       cout << *iter << "\n";
>    }
>    for (iter=int_vec.begin()+1, i=0; iter<int_vec.end(); iter+=2, i++) {
>       *iter = i + 1;
>       cout << *iter << "\n";
>    }
>    for (iter = int_vec.begin(); iter < int_vec.end(); iter++)
>       cout << *iter;
>    cout << "\n";
> }
>
> and it seems to work even if it seems it has no sense (infact i don't
> remember i used an iteration like this one, but i see many in exams texts
> ;) ).

It worked because the iterator for vector<> is a random access iterator,
with, so the comparison operators are defined for them. Your example
would not work on, for instance, a list<>.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Steve Cowan" <XXXscowan@binary.net>
Date: 1998/07/20
Raw View
Vector containers might work, assuming an increasing iterator, but lists,
sets, and maps fail terribly using '<', since the memory is not guarenteed
to be in increasing order.

MOTU - I planned to set a goal to fix my procrastination

Glen Perkins wrote in message <6oogco$db6$1@news.ncal.verio.com>...
>I'm a newbie STL user, and I'm curious about something.
>
>For years, the standard idiom for a for loop has been something like:
>
>for(int i = 0; i < 10; ++i) {...}
>
>Why do iterators do it with a not-equals instead of a less-than, i.e.
>
>for(iter = vec.begin(); iter != vec.end(); ++iter) {...}
>
>The plain int version works with !=, too, but the standard idiom has always
>been to use a less-than (experience with floating point comparison just
>makes that way "feel" safer.) Likewise, the vector iterator above works (or
>seems to me to work) fine with a less-than, but all sample code I see that
>uses iterators uses a not-equals instead.
>
>Is the less than operator undefined or otherwise unusable for some of the
>containers' iterators?
>
>Thanks,
>__Glen Perkins__






[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/07/21
Raw View
In article <6oogco$db6$1@news.ncal.verio.com>,
  "Glen Perkins" <gperkins+uaa@memwizard.com> wrote:
> I'm a newbie STL user, and I'm curious about something.
>
> For years, the standard idiom for a for loop has been something like:
>
> for(int i = 0; i < 10; ++i) {...}
>
> Why do iterators do it with a not-equals instead of a less-than, i.e.
>
> for(iter = vec.begin(); iter != vec.end(); ++iter) {...}
>
> The plain int version works with !=, too, but the standard idiom has always
> been to use a less-than (experience with floating point comparison just
> makes that way "feel" safer.) Likewise, the vector iterator above works (or
> seems to me to work) fine with a less-than, but all sample code I see that
> uses iterators uses a not-equals instead.
>
> Is the less than operator undefined or otherwise unusable for some of the
> containers' iterators?

Yes, that's it exactly.  Very perceptive.

vector<>::iterator is a random-access iterator, so operator< works
correctly.  However, operator< isn't even defined for the other four
iterator types.  So, for instance, if the for() loop above used a
list instead of a vector, it wouldn't compile properly.

In situations where you know that the iterator must be random-access,
you can use < instead of != if you prefer.  But, by the same reasoning
that made you "get in the habit" of using < for numeric loops, you
should probably "get in the habit" of using != for iterator loops
(and that would include plain-'ol-pointers, too).  I believe that this
is the reason why all the sample code you see uses != instead of <.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Michel Michaud" <Michel.Michaud@sympatico.ca>
Date: 1998/07/18
Raw View
Glen Perkins wrote:
>I'm a newbie STL user, and I'm curious about something.
>
>For years, the standard idiom for a for loop has been something like:
>
>for(int i = 0; i < 10; ++i) {...}
>
>Why do iterators do it with a not-equals instead of a less-than, i.e.
>
>for(iter = vec.begin(); iter != vec.end(); ++iter) {...}
>
>The plain int version works with !=, too, but the standard idiom has always
>been to use a less-than (experience with floating point comparison just
>makes that way "feel" safer.) Likewise, the vector iterator above works (or
>seems to me to work) fine with a less-than, but all sample code I see that
>uses iterators uses a not-equals instead.
>
>Is the less than operator undefined or otherwise unusable for some of the
>containers' iterators?
>
To work, the less-than needs to compare iterator (or pointer) that are
ordered. It is probable with vector<> because iterators are probably
pointers into a single buffer allocated for the elements (though it is not
stated in the standard). However, the whole thing with standard containers
is that algorithms (yours and those in <algorithm>) should work with
every type of container that support the operation you need. So if you
only need to inspect every element, a forward iterator is the only
thing that you need. There is one in list<>, set<> even map<>...

However you cannot expect that the elements are contiguous in all
containers.
So ++iter moves the iterator by following the logic necessary in the
container, it does not add 1 to a simple pointer. Imagine that list<> are
a linked list and that maps are some kind of tree.

If you need a simpler answer, well, < is not necessarly defined for
iterator (only with random access iterators, in vector<> and deque<>). Also
end() yields a special value (possibly like a null-pointer) so it is not
"greater-than" other iterator...

So the real question is, should we use != everywhere or
only with iterators? And my answer is, use != for uniformity and you'll
be able to change easily from an array[] to a vector<> or list<>, if
necessary. You'll also get used to the new idiom. However it seems
this is not what people do right now (if you check new books like
Stroustrup's or Lippman's). So the old idiom is still used in
for(int i=0; i<N; ++i) because i is not an iterator...

Michel Michaud micm19@mail2.cstjean.qc.ca
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: herbs@cntc.com (Herb Sutter)
Date: 1998/07/19
Raw View
"Glen Perkins" <gperkins+uaa@memwizard.com> wrote:
>Why do iterators do it with a not-equals instead of a less-than, i.e.

>The plain int version works with !=, too, but the standard idiom has always
>been to use a less-than (experience with floating point comparison just
>makes that way "feel" safer.)

Iterators aren't like floating-point numbers, because the positions are
distinct.

>Likewise, the vector iterator above works (or
>seems to me to work) fine with a less-than, but all sample code I see that
>uses iterators uses a not-equals instead.

As it should. Here's an exercise that will help you understand the reason:

  "Write operator< for list<T>::iterators."


---
Herb Sutter (mailto:herbs@cntc.com)

Current Network Technologies Corp  2695 North Sheridan Way, Suite 150
www.cntc.com www.peerdirect.com    Mississauga Ontario Canada L5K 2N6


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Glen Perkins" <gperkins+uaa@memwizard.com>
Date: 1998/07/18
Raw View
I'm a newbie STL user, and I'm curious about something.

For years, the standard idiom for a for loop has been something like:

for(int i = 0; i < 10; ++i) {...}

Why do iterators do it with a not-equals instead of a less-than, i.e.

for(iter = vec.begin(); iter != vec.end(); ++iter) {...}

The plain int version works with !=, too, but the standard idiom has always
been to use a less-than (experience with floating point comparison just
makes that way "feel" safer.) Likewise, the vector iterator above works (or
seems to me to work) fine with a less-than, but all sample code I see that
uses iterators uses a not-equals instead.

Is the less than operator undefined or otherwise unusable for some of the
containers' iterators?

Thanks,
__Glen Perkins__
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]