Initializing iterators to one past end() in for loops

N

Nikos Chantziaras

Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i < vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.
 
K

Kai-Uwe Bux

Nikos said:
Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i < vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.


Iterators for std::vector<> are random access. Hence, they are <-comparable
and you can add integers to them. So, you should be able to translate one-
to-one:

for ( std::vector<int>::iterator iter = vec.begin() + 1;
iter < vec.end(); ++ iter ) {
// do something with *iter
}

The stop-condition iter != vec.end() is broken for empty vectors.


Best,

Kai-Uwe Bux
 
G

gwowen

   typedef std::vector<int>::iterator it_t;
   for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
       // do something with *i

Unless you've got an empty vector, that should pretty much do it,
unless the "do something with it" modifies the vector in such a way to
invalidate the iterator (inserting elements will do this). If you have
an empty vector, vec.begin() == vec.end(), so vec.begin() + 1 will be
beyond the allowable range of iterators and bad things will happen.

[To operate on every element want vec.begin(), not vec.begin() + 1 but
you seem to be deliberately omitting the first element in both code
samples, so I'm going to assume thats intentional.]
 
N

Nikos Chantziaras

Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i < vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.


Thanks for all the responses. But I've made a mistake in my provided
example :p In the second loop, I'm using an std::list, not a vector:

std::list<int> lst;
typedef std::list<int>::iterator it_t;
for (it_t i = lst.begin() + 1; i != lst.end(); ++i)
// do something with *i

(Converting some vectors to lists was the reason I came across this in
the first place.)

I know it's not difficult to simply do something like:

it_t i = lst.begin();
++i;
for ( ; i != lst.end(); ++i)

but I was wondering whether there's some neat way to do that inside the
for header, so that 'i' will not stay in scope after the loop.
 
I

Ian Collins

Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i < vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.


Thanks for all the responses. But I've made a mistake in my provided
example :p In the second loop, I'm using an std::list, not a vector:

std::list<int> lst;
typedef std::list<int>::iterator it_t;
for (it_t i = lst.begin() + 1; i != lst.end(); ++i)
// do something with *i

(Converting some vectors to lists was the reason I came across this in
the first place.)

I know it's not difficult to simply do something like:

it_t i = lst.begin();
++i;
for ( ; i != lst.end(); ++i)


That would be the usual way.
but I was wondering whether there's some neat way to do that inside the
for header, so that 'i' will not stay in scope after the loop.

Put the operation in its own scope (a function maybe)?
 
K

Kai-Uwe Bux

Leigh said:
Nikos said:
Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i< vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.


Iterators for std::vector<> are random access. Hence, they
are<-comparable and you can add integers to them. So, you should be able
to translate one- to-one:

for ( std::vector<int>::iterator iter = vec.begin() + 1;
iter< vec.end(); ++ iter ) {
// do something with *iter
}


If the vector is empty then surely vec.begin() + 1 is UB?


Hm, my first impulse was to say: "oh, true; that kills it". However, upon
looking up table 76 in the standard, it appears that

r += n

has no pre-condition (like r is dereferencable). Now, r+n is defined in
terms of r += n. Also, the dereferencability precondition is mentioned at
other places (e.g., for ++r in table 74 about forward iterators). So, maybe
vec.begin()+1 is not undefined behavior after all. Of course, it could also
be an omission in the standard, or it could be that I am too tired to figure
it out correctly.


Best,

Kai-Uwe Bux
 
G

gwowen

I know it's not difficult to simply do something like:

   it_t i = lst.begin();
   ++i;
   for ( ; i != lst.end(); ++i)

but I was wondering whether there's some neat way to do that inside the
for header, so that 'i' will not stay in scope after the loop.

Off the top of my, head and completely untested:

for(it_t it=l.begin(); ++it != l.end();){
std::cout << *it << std::endl;
}

(Again, you need to make sure you have started with an empty list...)

for(it_t it=l.begin(); (it != l.end() && ++it != l.end());){
std::cout << *it << std::endl;
}

It's not pretty, but it might work ;) Seems quite an ugly way to do it
when you can create a scope specifically for the iterator at the cost
of typing two braces.
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
Leigh said:
Nikos Chantziaras wrote:

Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i< vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.

Iterators for std::vector<> are random access. Hence, they
are<-comparable and you can add integers to them. So, you should be able
to translate one- to-one:

for ( std::vector<int>::iterator iter = vec.begin() + 1;
iter< vec.end(); ++ iter ) {
// do something with *iter
}


If the vector is empty then surely vec.begin() + 1 is UB?


Hm, my first impulse was to say: "oh, true; that kills it". However, upon
looking up table 76 in the standard, it appears that

r += n

has no pre-condition (like r is dereferencable). Now, r+n is defined in
terms of r += n. Also, the dereferencability precondition is mentioned at
other places (e.g., for ++r in table 74 about forward iterators). So,
maybe vec.begin()+1 is not undefined behavior after all. Of course, it
could also be an omission in the standard, or it could be that I am too
tired to figure it out correctly.


Seems, it was the third option:

[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 non-singular.

Hence, vec.begin()+1 is not UB (as vec.begin() is non-singular), but
assigning the resulting singular value to the iterator variable iter is UB.


Best,

Kai-Uwe Bux
 
N

Noah Roberts

Kai-Uwe Bux said:
Leigh said:
On 13/04/2011 22:48, Kai-Uwe Bux wrote:
Nikos Chantziaras wrote:

Is there some simple way to convert this:

std::vector<int> vec;
// ...
for (size_t i = 1; i< vec.size(); ++i)
// do something with vec

to a for-loop that uses iterators? I've tried:

typedef std::vector<int>::iterator it_t;
for (it_t i = vec.begin() + 1; i != vec.end(); ++i)
// do something with *i

but I'm not surprised that it doesn't work.

Iterators for std::vector<> are random access. Hence, they
are<-comparable and you can add integers to them. So, you should be able
to translate one- to-one:

for ( std::vector<int>::iterator iter = vec.begin() + 1;
iter< vec.end(); ++ iter ) {
// do something with *iter
}

If the vector is empty then surely vec.begin() + 1 is UB?


Hm, my first impulse was to say: "oh, true; that kills it". However, upon
looking up table 76 in the standard, it appears that

r += n

has no pre-condition (like r is dereferencable). Now, r+n is defined in
terms of r += n. Also, the dereferencability precondition is mentioned at
other places (e.g., for ++r in table 74 about forward iterators). So,
maybe vec.begin()+1 is not undefined behavior after all. Of course, it
could also be an omission in the standard, or it could be that I am too
tired to figure it out correctly.


Seems, it was the third option:

[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 non-singular.

Hence, vec.begin()+1 is not UB (as vec.begin() is non-singular), but
assigning the resulting singular value to the iterator variable iter is UB.


The problem here though is that if you where interpreting correctly then
pointers could not be iterators since (arr + sizeof(arr))++ is UB.

Luckily I believe you're interpreting incorrectly. The quote you show
there quite explicitly calls "most expressions are undefined...". The
only exception it provides is assignment FROM a non-singular. It seems
to be quite clearly illustrating that default constructed and
uninitialized iterators can exist but that you'd better not do anything
with them but assign to them from a valid iterator value that actually
iterates something. Further it isn't allowing for incrementing an
iterator past end().
 
I

Ian Collins

std::list<int> lst;
typedef std::list<int>::iterator it_t;
// populate list

if (!lst.empty()) {
for (it_t i = std::next(lst.begin()); i != lst.end(); ++i) {

For those using C++0x compilers!
 
N

Noah Roberts

Noah said:
Kai-Uwe Bux wrote:
Seems, it was the third option:

[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 non-singular.

Hence, vec.begin()+1 is not UB (as vec.begin() is non-singular), but
assigning the resulting singular value to the iterator variable iter is
UB.

The problem here though is that if you where interpreting correctly then
pointers could not be iterators since [incrementing past the past-the-end iterator] is UB.

a) Why would that be UB according to my interpretation of [24.1/5]?

It's not. It's UB because incrementing a pointer beyond what the
standard explicitly allows (for example 1 past the end of an array) is
UB. Thus if your interpretation of the quoted bits where accurate,
c) Why would it be bad if this expression involved UB?

Practically speaking, most of the time, you probably wouldn't notice any
unexpected behavior from this particular kind of UB.
Exactly. I have a cold, so maybe my brain is not working properly; but the
way I read [24.1/5] is as follows:

iterator iter = vec.begin(); // iter holds non-singular value.
vec.begin() + 1; // vec.begin() is a non-singular operand
iter = vec.begin() + 1; // if vec is empty, the rhs is singular.
// the operation of assignment is UB.

24.1/5 isn't actually saying anything about "non-singular values" except
how assignment of them into previously singular iterators works. You
can't use 24.1/5 as evidence that vec.begin() + 1 is defined when
vec.empty() == true.
It seems
to be quite clearly illustrating that default constructed and
uninitialized iterators can exist but that you'd better not do anything
with them but assign to them from a valid iterator value that actually
iterates something. Further it isn't allowing for incrementing an
iterator past end().

Well, vec.end() is a non-singular value. Hence, the expression vec.end()+1
has a singular _result_ but the operands are non-singular. The way I read
[24.1/5] is that the result is defined although singular, i.e., I take the
phrase

Results of most expressions are undefined for singular values

to mean "undefined for singular values of the operands".

To show that it's not defined, we first have to realize that if it's not
defined by the standard it's as UB as if the standard specifically says
so. If you note table 76, r + n is defined in terms of r+= n, which is
defined in terms of r+n. r+n is defined in terms of ++r. The
precondition for r in this case is that it is dereferenceable (24.1/5.
Since end() is not, ++end() is not defined. Since ++end() is not
defined, neither is end() + n.

Based on these clauses and tables it would seem to me that the only way
to get "singular" iterators is to not initialize an iterator. There's
no defined way to get one from a non-singular iterator because any
operation that could create one is not defined to do anything in
particular by the standard. In some cases (and I've written them)
++end() will crash or do something really stupid like return end().
 
K

Kai-Uwe Bux

Noah said:
Noah said:
On 4/13/2011 3:32 PM, Kai-Uwe Bux wrote:
Kai-Uwe Bux wrote:
Seems, it was the third option:

[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
non-singular.

Hence, vec.begin()+1 is not UB (as vec.begin() is non-singular), but
assigning the resulting singular value to the iterator variable iter is
UB.

The problem here though is that if you where interpreting correctly then
pointers could not be iterators since [incrementing past the
past-the-end iterator] is UB.

a) Why would that be UB according to my interpretation of [24.1/5]?

It's not. It's UB because incrementing a pointer beyond what the
standard explicitly allows (for example 1 past the end of an array) is
UB. Thus if your interpretation of the quoted bits where accurate,
std::vector<T>::iterator could not be a pointer because past_end_ptr+1
is not defined, regardless of if its assigned to anything.

Just to make sure, I grok the logic here:

1) For a pointer, past_end_ptr+1 is undefined.

2) According to my interpretation, vec.end()+1 is defined (as long as not
assigned to anything).

3) Hence: std::vector<T>::iterator could not be a pointer.

I would phrase that point differently: under the proposed interpretation,
pointers would not satisfy the requirements for random access iterators.

c) Why would it be bad if this expression involved UB?

Practically speaking, most of the time, you probably wouldn't notice any
unexpected behavior from this particular kind of UB.
Exactly. I have a cold, so maybe my brain is not working properly; but
the way I read [24.1/5] is as follows:

iterator iter = vec.begin(); // iter holds non-singular value.
vec.begin() + 1; // vec.begin() is a non-singular operand
iter = vec.begin() + 1; // if vec is empty, the rhs is singular.
// the operation of assignment is UB.

24.1/5 isn't actually saying anything about "non-singular values" except
how assignment of them into previously singular iterators works. You
can't use 24.1/5 as evidence that vec.begin() + 1 is defined when
vec.empty() == true.
It seems
to be quite clearly illustrating that default constructed and
uninitialized iterators can exist but that you'd better not do anything
with them but assign to them from a valid iterator value that actually
iterates something. Further it isn't allowing for incrementing an
iterator past end().

Well, vec.end() is a non-singular value. Hence, the expression
vec.end()+1 has a singular _result_ but the operands are non-singular.
The way I read
[24.1/5] is that the result is defined although singular, i.e., I take
[the
phrase

Results of most expressions are undefined for singular values

to mean "undefined for singular values of the operands".

To show that it's not defined, we first have to realize that if it's not
defined by the standard it's as UB as if the standard specifically says
so. If you note table 76, r + n is defined in terms of r+= n, which is
defined in terms of r+n. r+n is defined in terms of ++r. The
precondition for r in this case is that it is dereferenceable (24.1/5.
Since end() is not, ++end() is not defined. Since ++end() is not
defined, neither is end() + n.

This definition in terms of ++r is what I missed. Thanks.

Based on these clauses and tables it would seem to me that the only way
to get "singular" iterators is to not initialize an iterator. There's
no defined way to get one from a non-singular iterator because any
operation that could create one is not defined to do anything in
particular by the standard. In some cases (and I've written them)
++end() will crash or do something really stupid like return end().

Yup, seems that way.


Best,

Kai-Uwe Bux
 
N

Nikos Chantziaras

Nikos Chantziaras said:
Thanks for all the responses. But I've made a mistake in my provided
example :p In the second loop, I'm using an std::list, not a vector:

std::list<int> lst;
typedef std::list<int>::iterator it_t;
for (it_t i = lst.begin() + 1; i != lst.end(); ++i)
// do something with *i

(Converting some vectors to lists was the reason I came across this in
the first place.)

I know it's not difficult to simply do something like:

it_t i = lst.begin();
++i;
for ( ; i != lst.end(); ++i)

but I was wondering whether there's some neat way to do that inside the
for header, so that 'i' will not stay in scope after the loop.
[...]

if (!lst.empty()) {
for (it_t i = std::next(lst.begin()); i != lst.end(); ++i) {
// do something
}
}

Yep, that looks nicer! It's C++0x, but seems to be supported well
enough by now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top