Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Initializing iterators to one past end() in for loops

Reply
Thread Tools

Initializing iterators to one past end() in for loops

 
 
Nikos Chantziaras
Guest
Posts: n/a
 
      04-13-2011
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[i]

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.
 
Reply With Quote
 
 
 
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      04-13-2011
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[i]
>
> 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
 
Reply With Quote
 
 
 
 
gwowen
Guest
Posts: n/a
 
      04-13-2011
On Apr 13, 10:38*pm, Nikos Chantziaras <(E-Mail Removed)> wrote:

> * *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.]
 
Reply With Quote
 
Nikos Chantziaras
Guest
Posts: n/a
 
      04-13-2011
On 04/14/2011 12:38 AM, 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[i]
>
> 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 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.
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      04-13-2011
On 04/14/11 10:07 AM, Nikos Chantziaras wrote:
> On 04/14/2011 12:38 AM, 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[i]
>>
>> 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 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)?

--
Ian Collins
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      04-13-2011
Leigh Johnston wrote:

> 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[i]
>>>
>>> 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
 
Reply With Quote
 
gwowen
Guest
Posts: n/a
 
      04-13-2011
On Apr 13, 11:07*pm, Nikos Chantziaras <(E-Mail Removed)> wrote:
> 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.
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      04-13-2011
Kai-Uwe Bux wrote:

> Leigh Johnston wrote:
>
>> 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[i]
>>>>
>>>> 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

 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      04-14-2011
On 4/13/2011 3:32 PM, Kai-Uwe Bux wrote:
> Kai-Uwe Bux wrote:
>
>> Leigh Johnston wrote:
>>
>>> 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[i]
>>>>>
>>>>> 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().

--
http://crazycpp.wordpress.com
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      04-14-2011
On 04/14/11 04:05 PM, Paavo Helde wrote:
> Nikos Chantziaras<(E-Mail Removed)> wrote in news:io56qc$cu8$1
> @news.grnet.gr:
>> Thanks for all the responses. But I've made a mistake in my provided
>> example 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.

>
> 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!

--
Ian Collins
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
initializing an array from iterators Marc C++ 1 11-02-2010 02:26 PM
plain iterators and reverse iterators on vector subramanian100in@yahoo.com, India C++ 10 08-08-2009 08:28 AM
Forward iterators and past-the-end iterator Mark Stijnman C++ 5 01-28-2006 08:56 PM
Dereferencing past-the-end iterators Matthias Kaeppler C++ 2 07-22-2005 11:01 PM
Iterators and reverse iterators Marcin Kaliciński C++ 1 05-08-2005 09:58 AM



Advertisments