Address one past the end of array - is this syntax a valid C++?

P

Peter

Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to refer toelement arr[5] as it's not part of the array. However, arr + n is equivalent to &arr[n]. My question is: does this equivalence also hold for an edge case of
n = 5 (or, generally, n equal to number of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly suspicious: it looks like in the first step arr[5] is evaluated (which introduces an undefined behaviour) which would mean the expression as a whole is undefined.Does the equivalence still hold in this special case?
 
V

Victor Bazarov

Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to
refer to element arr[5] as it's not part of the array. However, arr +
n is equivalent to &arr[n]. My question is: does this equivalence
also hold for an edge case of n = 5 (or, generally, n equal to number
of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is evaluated
(which introduces an undefined behaviour) which would mean the
expression as a whole is undefined. Does the equivalence still hold
in this special case?

I would not be surprised at the validity of this after I've learned that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it. So, using the same logic, the
expression a[n] is the same as *(a+n), which is to give you a reference
to a non-existing element (one beyond the last in the array) and with
that reference the only valid operation is to take its address.
According to the precedence rules, &arr[5] is evaluated as &(*(arr+5)),
which is OK (if you subscribe to the invalid reference idea and the
validity of applying the 'address of' operator to it).

V
 
B

bblaz

Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to
refer to element arr[5] as it's not part of the array. However, arr +
n is equivalent to &arr[n]. My question is: does this equivalence
also hold for an edge case of n = 5 (or, generally, n equal to number
of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is evaluated
(which introduces an undefined behaviour) which would mean the
expression as a whole is undefined. Does the equivalence still hold
in this special case?

I would not be surprised at the validity of this after I've learned that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it. So, using the same logic, the
expression a[n] is the same as *(a+n), which is to give you a reference
to a non-existing element (one beyond the last in the array) and with
that reference the only valid operation is to take its address.
According to the precedence rules, &arr[5] is evaluated as &(*(arr+5)),
which is OK (if you subscribe to the invalid reference idea and the
validity of applying the 'address of' operator to it).

Bullshit mate; dereferencing null pointers is UB.

/Flibble

Not always true.

Dereferencing pointers which do not point to valid objects is undefined
behavior if the program necessitates the lvalue-to-rvalue conversion of
the *arr expression.
see 4.1 #1.

5.3.1 #3
The result of the unary & operator is a pointer to its operand. The
operand shall be either an lvalue of type
other than “array of runtime bound†or a qualified-id.

Evaluation of &*arr expression does not necessitate the lvalue-to-rvalue
conversion, hence its legal.


Also 5.3.1 #1
The unary * operator performs indirection: the expression to which it is
applied shall be a pointer to an
object type, or a pointer to a function type and the result is an lvalue
referring to the object or function
to which the expression points. If the type of the expression is
“pointer to T,†the type of the result is
“T.†[ Note: indirection through a pointer to an incomplete type (other
than cv void) is valid. The lvalue
thus obtained can be used in limited ways (to initialize a reference,
for example); this lvalue must not be
converted to a prvalue, see 4.1. — end note ]

blaz
 
D

Dombo

Op 01-Feb-14 23:36, Victor Bazarov schreef:
Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to
refer to element arr[5] as it's not part of the array. However, arr +
n is equivalent to &arr[n]. My question is: does this equivalence
also hold for an edge case of n = 5 (or, generally, n equal to number
of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is evaluated
(which introduces an undefined behaviour) which would mean the
expression as a whole is undefined. Does the equivalence still hold
in this special case?

I would not be surprised at the validity of this after I've learned that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it. So, using the same logic, the
expression a[n] is the same as *(a+n), which is to give you a reference
to a non-existing element (one beyond the last in the array) and with
that reference the only valid operation is to take its address.
According to the precedence rules, &arr[5] is evaluated as &(*(arr+5)),
which is OK (if you subscribe to the invalid reference idea and the
validity of applying the 'address of' operator to it).

I'm not sure this is the case; according to the C++ 11 draft standard
(N3337): "Note: std::nullptr_t is a distinct type that is neither a
pointer type nor a pointer to member type; rather, a prvalue of this
type is a null pointer constant and can be converted to a null pointer
value or null member pointer value.". I.e. since nullptr is not a
pointer type the fact that you can legally dereference it (which
surprised me a bit, but I suppose there is a good reason for it),
doesn't necessarily mean that it is also legal to dereference a pointer
referencing a non-existing element.
 
B

bblaz

On 01/02/2014 22:36, Victor Bazarov wrote:
On 2/1/2014 12:23 PM, Peter wrote:
Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to
refer to element arr[5] as it's not part of the array. However, arr +
n is equivalent to &arr[n]. My question is: does this equivalence
also hold for an edge case of n = 5 (or, generally, n equal to number
of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is evaluated
(which introduces an undefined behaviour) which would mean the
expression as a whole is undefined. Does the equivalence still hold
in this special case?

I would not be surprised at the validity of this after I've learned
that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it. So, using the same logic,
the
expression a[n] is the same as *(a+n), which is to give you a reference
to a non-existing element (one beyond the last in the array) and with
that reference the only valid operation is to take its address.
According to the precedence rules, &arr[5] is evaluated as &(*(arr+5)),
which is OK (if you subscribe to the invalid reference idea and the
validity of applying the 'address of' operator to it).

Bullshit mate; dereferencing null pointers is UB.

/Flibble

Not always true.

More bullshit. It is always true mate; dereferencing null pointers is UB.

8.3.2/5

"A reference shall be initialized to refer to a valid object
or function. [ Note: in particular, a null reference cannot exist in a
well-defined program, because the only
way to create such a reference would be to bind it to the “objectâ€
obtained by dereferencing a null pointer,
which causes undefined behavior. As described in 9.6, a reference cannot
be bound directly to a bit-field.
—end note ]"

[snipped unrelated Standard quotes]

/Flibble

& is an unary operator & not a reference type. I think your quote is
irrelevant in this case.

blaz
 
B

bblaz

On 02/02/14 00:33, Mr Flibble wrote:
On 01/02/2014 22:36, Victor Bazarov wrote:
On 2/1/2014 12:23 PM, Peter wrote:
Assume we have an array:

int arr[5];

It's legal to refer to address arr + 5, but, of course, illegal to
refer to element arr[5] as it's not part of the array. However, arr +
n is equivalent to &arr[n]. My question is: does this equivalence
also hold for an edge case of n = 5 (or, generally, n equal to number
of elements of array)?

While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is evaluated
(which introduces an undefined behaviour) which would mean the
expression as a whole is undefined. Does the equivalence still hold
in this special case?

I would not be surprised at the validity of this after I've learned
that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it. So, using the same logic,
the
expression a[n] is the same as *(a+n), which is to give you a
reference
to a non-existing element (one beyond the last in the array) and with
that reference the only valid operation is to take its address.
According to the precedence rules, &arr[5] is evaluated as
&(*(arr+5)),
which is OK (if you subscribe to the invalid reference idea and the
validity of applying the 'address of' operator to it).

Bullshit mate; dereferencing null pointers is UB.

/Flibble

Not always true.

More bullshit. It is always true mate; dereferencing null pointers is UB.

8.3.2/5

"A reference shall be initialized to refer to a valid object
or function. [ Note: in particular, a null reference cannot exist in a
well-defined program, because the only
way to create such a reference would be to bind it to the “objectâ€
obtained by dereferencing a null pointer,
which causes undefined behavior. As described in 9.6, a reference cannot
be bound directly to a bit-field.
—end note ]"

[snipped unrelated Standard quotes]

/Flibble

& is an unary operator & not a reference type. I think your quote is
irrelevant in this case.

blaz

To be clear, i was refering to the op.
 
J

James Kanze

Assume we have an array:
int arr[5];
It's legal to refer to address arr + 5, but, of course,
illegal to refer to element arr[5] as it's not part of the
array. However, arr + n is equivalent to &arr[n].

No it's not. They're only equivalent if the expression "arr[n]"
is a valid expression.
My question
is: does this equivalence also hold for an edge case of
n = 5 (or, generally, n equal to number of elements of array)?
While there's nothing wrong with arr + 5, &arr[5] looks highly
suspicious: it looks like in the first step arr[5] is
evaluated (which introduces an undefined behaviour) which
would mean the expression as a whole is undefined.
Exactly.

Does the
equivalence still hold in this special case?

No. "arr + 5" is legal, and corresponds to a pointer one beyond
the end of the array. "&arr[5]" is undefined behavior.

C has a special rule to allow "&arr[5]". Back before C++03 (and
even before C++98, I think), there was some discussion about
allowing this in C++, but in the end, the special case was not
adopted. (I think part of the motivation for not adopting it is
that you couldn't make it work with user defined containers,
like std::vector. Something like:

std::vector<int> v(5);
int* p = &v[5];

will crash, at least in debug mode, in all of the
implementations I use.)
 
J

James Kanze

]
I would not be surprised at the validity of this after I've learned that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it.

Just curious, but where did you get this information from?
I can't find it in the standard (looking in the obvious places,
which isn't always enough).
 
V

Victor Bazarov

]
I would not be surprised at the validity of this after I've learned that
initializing a reference by dereferencing a null pointer is now legal.
*nullptr creates a special kind of reference, and the only useful
operation you can do with it is to take its address, which in turn
should give you null, as I understand it.

Just curious, but where did you get this information from?
I can't find it in the standard (looking in the obvious places,
which isn't always enough).

I can't give you the exact source, unfortunately, and I am sorry. All I
can remember is that it was mentioned here, discussed in some thread,
and at the time my claim of undefined behavior of initializing a
reference by dereferencing a null pointer was contradicted, and upon
investigating I found that the lvalue to rvalue conversion that used to
be necessary and was the cause of the UB in such a case was not any
longer a requirement (or it was that I incorrectly remembered that
conversion was needed). And in a blink of an eye, so to speak, UB was
not there anymore.

I'm likely too gullible when C++ is concerned. Next you're going to
tell me that atoi is not a standard function, and I'll believe it. :)

V
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top