Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is accesing rend().base() an U.B. ?

19 views
Skip to first unread message

abhay...@gmail.com

unread,
Mar 5, 2009, 5:10:50 AM3/5/09
to
Hello Group,

I wanted some clarification w.r.t. reverse_iterator. Plz have a look
at the following snippet

// start_snip
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>

using std::cout;
using std::vector;

int main(){
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
typedef vector<int> myVec;
myVec vec(arr, arr + sizeof(arr)/sizeof(arr[0]) );

myVec::reverse_iterator riter = vec.rbegin();
cout<<*riter<<"\n"; // prints 10
//cout<<*riter.base()<<"\n"; // this will crash (on VC 2005)
riter = riter + 4;
cout<<*riter<<"\n"; // prints 6
cout<<*riter.base()<<"\n"; // this prints 7

cout<<*vec.rend().base()<<"\n"; // prints 1, Is VC++ correct here?

// both asserts below succeed
assert(vec.rbegin().base() == vec.end());
assert(vec.rend().base() == vec.begin());

return 0;
}
// End_snip

The base iterator always points to one after the reverse iterator.
This is
to facilitate the one-before-beginning requirement for rend(), i
guess. And the operator*
for reverse_iterator does the behind-the-scenes job of retreating one
position
before the current iter.

What does the standard say abt accessing one-before-begining for
reverse_iterators?
IIRC, for forward iterators, both accessing one before begining and
the element at end()
is an UB.

Thanks in advance
Abhay

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ulrich Eckhardt

unread,
Mar 6, 2009, 3:22:26 AM3/6/09
to
abhay...@gmail.com wrote:
> int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
> typedef vector<int> myVec;
> myVec vec(arr, arr + sizeof(arr)/sizeof(arr[0]) );
>
> myVec::reverse_iterator riter = vec.rbegin();
> cout<<*riter<<"\n"; // prints 10
> //cout<<*riter.base()<<"\n"; // this will crash (on VC 2005)
> riter = riter + 4;
> cout<<*riter<<"\n"; // prints 6
> cout<<*riter.base()<<"\n"; // this prints 7
>
> cout<<*vec.rend().base()<<"\n"; // prints 1, Is VC++ correct here?

Yes:

_ 1 2 3 4 5 6 7 _
^begin ^end
^rend ^rbegin
^rend.base ^rbegin.base

> // both asserts below succeed
> assert(vec.rbegin().base() == vec.end());
> assert(vec.rend().base() == vec.begin());

This documents exactly the intended relation between a reverse iterator and
its base.

Now, why is that the case? The reason is that for an array, pointers to all
elements plus the one to the element past the end are valid pointers (even
though the last one is not dereferenceable). However, the pointer to the
element before the first one is not a valid pointer value, so in order to
get an end-iterator for reverse iterators, you have to use the offset of 1.

Note the distinction between valid pointer value and dereferenceable
pointer. Pointers to elements are both, pointer to one past the end is only
a valid value while one before the beginning is neither.

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932

Bo Persson

unread,
Mar 6, 2009, 11:40:43 AM3/6/09
to
abhay...@gmail.com wrote:
> Hello Group,
>
> I wanted some clarification w.r.t. reverse_iterator. Plz have a look
> at the following snippet
>
> // start_snip
> #include <iostream>
> #include <vector>
> #include <algorithm>
> #include <cassert>
>
> using std::cout;
> using std::vector;
>
> int main(){
> int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
> typedef vector<int> myVec;
> myVec vec(arr, arr + sizeof(arr)/sizeof(arr[0]) );
>
> myVec::reverse_iterator riter = vec.rbegin();
> cout<<*riter<<"\n"; // prints 10
> //cout<<*riter.base()<<"\n"; // this will crash (on VC 2005)
> riter = riter + 4;
> cout<<*riter<<"\n"; // prints 6
> cout<<*riter.base()<<"\n"; // this prints 7
>
> cout<<*vec.rend().base()<<"\n"; // prints 1, Is VC++ correct
> here?

Yes. You get the base of vec.rend(), which is obviously vec.begin().
Accessing that yields 1.

>
> // both asserts below succeed
> assert(vec.rbegin().base() == vec.end());
> assert(vec.rend().base() == vec.begin());
>
> return 0;
> }
> // End_snip
>
> The base iterator always points to one after the reverse iterator.
> This is
> to facilitate the one-before-beginning requirement for rend(), i
> guess. And the operator*
> for reverse_iterator does the behind-the-scenes job of retreating
> one position
> before the current iter.
>
> What does the standard say abt accessing one-before-begining for
> reverse_iterators?

You cannot access (deference) anything either before or after the
sequence. :-)

> IIRC, for forward iterators, both accessing one before begining and
> the element at end()
> is an UB.
>

For any iterator!


Bo Persson

Greg Herlihy

unread,
Mar 7, 2009, 10:24:22 AM3/7/09
to
On Mar 5, 2:10 am, abhay.bu...@gmail.com wrote:
> Hello Group,

> using std::cout;
> using std::vector;
>
> int main(){
> int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
> typedef vector<int> myVec;
> myVec vec(arr, arr + sizeof(arr)/sizeof(arr[0]) );
>
> myVec::reverse_iterator riter = vec.rbegin();
> cout<<*riter<<"\n"; // prints 10
> //cout<<*riter.base()<<"\n"; // this will crash (on VC 2005)
> riter = riter + 4;
> cout<<*riter<<"\n"; // prints 6
> cout<<*riter.base()<<"\n"; // this prints 7
>
> cout<<*vec.rend().base()<<"\n"; // prints 1, Is VC++ correct here?

Yes.

> // both asserts below succeed
> assert(vec.rbegin().base() == vec.end());
> assert(vec.rend().base() == vec.begin());

Both asserts must be true.

> The base iterator always points to one after the reverse iterator.

Not really. The "base" of a reverse_iterator is the iterator being
"wrapped" by the particular reverse_iterator instance. Note however
that dereferencing a reverse_iterator does not in turn dereference its
wrapped iterator - but instead dereferences the iterator immediately
preceding.

So, for example, a container's rbegin() method returns a
reverse_iterator that "wraps" the iterator returned by the container's
end() method. But *rbegin() does not dereference the wrapped end()
iterator (which would have undefined behavior) but the iterator
before, that is, end()-1. Therefore, it is OK to dereference all the
reverse iterators between rbegin() up to (but not including) rend(),
just as it is OK to dereference all the iterators from begin() up to
(but not including) end().

> What does the standard say abt accessing one-before-begining for
> reverse_iterators?
> IIRC, for forward iterators, both accessing one before begining and
> the element at end()
> is an UB.

The rules for reverse_iterators are the same as for forward iterators.
Namely, both *rend() and --rbegin() are undefined - just as *end() and
--begin() are undefined.

Greg

0 new messages