Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Initializing iterators to one past end() in for loops (http://www.velocityreviews.com/forums/t746773-initializing-iterators-to-one-past-end-in-for-loops.html)

 Nikos Chantziaras 04-13-2011 09:38 PM

Initializing iterators to one past end() in for loops

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.

 Kai-Uwe Bux 04-13-2011 09:48 PM

Re: Initializing iterators to one past end() in for loops

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

 gwowen 04-13-2011 09:49 PM

Re: Initializing iterators to one past end() in for loops

On Apr 13, 10:38*pm, Nikos Chantziaras <rea...@arcor.de> 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.]

 Nikos Chantziaras 04-13-2011 10:07 PM

Re: Initializing iterators to one past end() in for loops

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 :-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.

 Ian Collins 04-13-2011 10:12 PM

Re: Initializing iterators to one past end() in for loops

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 :-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)?

--
Ian Collins

 Kai-Uwe Bux 04-13-2011 10:23 PM

Re: Initializing iterators to one past end() in for loops

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

 gwowen 04-13-2011 10:24 PM

Re: Initializing iterators to one past end() in for loops

On Apr 13, 11:07*pm, Nikos Chantziaras <rea...@arcor.de> 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.

 Kai-Uwe Bux 04-13-2011 10:32 PM

Re: Initializing iterators to one past end() in for loops

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

 Noah Roberts 04-14-2011 12:16 AM

Re: Initializing iterators to one past end() in for loops

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

 Ian Collins 04-14-2011 04:20 AM

Re: Initializing iterators to one past end() in for loops

On 04/14/11 04:05 PM, Paavo Helde wrote:
> Nikos Chantziaras<realnc@arcor.de> wrote in news:io56qc\$cu8\$1
> @news.grnet.gr:
>> 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.

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

All times are GMT. The time now is 06:53 AM.