Incrementing a pointer to a one-past-the-end value?

B

BigMan

I wonder if the C++ standard says what should happen if I increment a
pointer to a one-past-the-end value.
I think it says that it is perfectly legal to increment a pointer to
the last element element in an array - I get a pointer to
one-past-the-end value. It is guaranteed that such a value exists for
any array, so I always get a valid pointer to something (I do not care
what it is).
So, my question is what if I go further and increment a pointer to a
one-past-the-end value? Do I still get a valid pointer to anything?
Let me illustrate my question with a piece of code:

int main
(
)
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here? Is p a valid pointer? And what if the array
was allocated dynamically?
}
 
R

Rob Williscroft

BigMan wrote in
in
comp.lang.c++:
So, my question is what if I go further and increment a pointer to a
one-past-the-end value? Do I still get a valid pointer to anything?
Let me illustrate my question with a piece of code:

int main
(
)
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here? Is p a valid pointer? And what if the
array
was allocated dynamically?

You have undefined behaviour, IOW the standard no longer defines what
will or will not happen, it could be Very Bad Things(tm) or nothing
at all.

HTH.

Rob.
 
B

Ben Pope

Rob said:
BigMan wrote in
in
comp.lang.c++:

So, my question is what if I go further and increment a pointer to a
one-past-the-end value? Do I still get a valid pointer to anything?
Let me illustrate my question with a piece of code:

int main
(
)
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here? Is p a valid pointer? And what if the
array
was allocated dynamically?


You have undefined behaviour, IOW the standard no longer defines what
will or will not happen, it could be Very Bad Things(tm) or nothing
at all.

Surely he only has undefined behaviour if he actually dereferences it?

Ben
 
R

Rob Williscroft

Ben Pope wrote in
in comp.lang.c++:
Rob said:
BigMan wrote in
in
comp.lang.c++:

So, my question is what if I go further and increment a pointer to a
one-past-the-end value? Do I still get a valid pointer to anything?
Let me illustrate my question with a piece of code:

int main
(
)
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here? Is p a valid pointer? And what if the
array
was allocated dynamically?


You have undefined behaviour, IOW the standard no longer defines what
will or will not happen, it could be Very Bad Things(tm) or nothing
at all.

Surely he only has undefined behaviour if he actually dereferences it?

If it isn't undefined, then surely it must be defined, so what does it
do ?

Rob.
 
O

Old Wolf

That's a new indenting style..
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here?


You have undefined behaviour, IOW the standard no longer defines what
will or will not happen, it could be Very Bad Things(tm) or nothing
at all.

Surely he only has undefined behaviour if he actually dereferences it?

No, the increment itself causes undefined behaviour.

As a rationale, consider these possibilities:
- a[] is the last object in memory (or the current segment)
- a+3 would be in a different process's address space

These possibilities are unlikely on an IA32 system with 4 Gigabytes
of RAM, but they are much more real on an embedded system.
 
B

Ben Pope

Rob said:
Ben Pope wrote in
in comp.lang.c++:

Rob said:
BigMan wrote in
in
comp.lang.c++:



So, my question is what if I go further and increment a pointer to a
one-past-the-end value? Do I still get a valid pointer to anything?
Let me illustrate my question with a piece of code:

int main
(
)
{
int a[ 2 ];
int* p = a;
++p; // OK, points to the second element (indexed 1).
++p; // OK, points to one-past-the-end value.
++p; // What happens here? Is p a valid pointer? And what if the
array
was allocated dynamically?


You have undefined behaviour, IOW the standard no longer defines what
will or will not happen, it could be Very Bad Things(tm) or nothing
at all.

Surely he only has undefined behaviour if he actually dereferences it?


If it isn't undefined, then surely it must be defined, so what does it
do ?

I guessed the pointer was equal to a + 3*sizeof(int), regardless of what is or isn't there, but presumably it doesn't, which is why dereferencing it is bad.

presumably thats why:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
i--;
i++;

Isn't guaranteed to point to *v.begin()?

Ben
 
R

Rob Williscroft

Ben Pope wrote in
in
comp.lang.c++:
I guessed the pointer was equal to a + 3*sizeof(int), regardless of
what is or isn't there, but presumably it doesn't, which is why
dereferencing it is bad.

There are implementations where you have ((p + n) - n) == p, for
any non-void pointer p and any int n. There are other implementations
where a pointer (in a register) that doesn't actually point to valid
memory causes some kind of fault.

On such an implementaion the call (new int[10]) will need to allocate
11 int's just to make sure the one-passed-the-end rule is valid.

All implemetations need to avoid allocating the top of memory as
the last element of an array, as otherwise the requirment:

some_type array[N];
assert( (array + N) > (array + 0) );

i.e. the one-passed-the-end rule, will fail.


The point I'm trying to make is that undefined behaviour has
a plus side, the language is effeciently portable to a greater
number of platforms becuase of it.

For example, if the language allowed arbitary additions and
subtractions from pointers then platforms with checked pointer
registers would need to store and do all there arithmatic in
non-pointer registers, and then only load these values into the
pointer registers when dereferencing. This is against the
"Don't pay for what you don't use", "Spirit of C" that C++ inherited.
presumably thats why:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();

Undefined Behaviour starts here:

All bets are now off.
i++;

Isn't guaranteed to point to *v.begin()?

Its worse than that, there is nolonger anything gauranteed.

undefined-behaviour,-it-really-does-what-it-says-on-the-tin-ly yr's Rob.
 
B

Ben Pope

Rob said:
There are implementations where you have ((p + n) - n) == p, for
any non-void pointer p and any int n. There are other implementations
where a pointer (in a register) that doesn't actually point to valid
memory causes some kind of fault.
The point I'm trying to make is that undefined behaviour has
a plus side, the language is effeciently portable to a greater
number of platforms becuase of it.

For example, if the language allowed arbitary additions and
subtractions from pointers then platforms with checked pointer
registers would need to store and do all there arithmatic in
non-pointer registers, and then only load these values into the
pointer registers when dereferencing. This is against the
"Don't pay for what you don't use", "Spirit of C" that C++ inherited.

Ahh yes, of course.

I wasn' thinking in terms of platforms that might do that.

Very interesting, thanks.

P.S., sorry for the delay in replying, news server started denying me access for no apparent reason. It's just slow now.

Ben
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top