J
James Kanze
The former dereferences a pointer to a nonexisting element."Francesco"
Could you please explain me why it isn't good to use
"&from[Nfrom]", being that "from + Nfrom" is just
exactly the same thing, and since the standard allows me
to take the address of the first element past the array
in either way? Am I mistaking the standard or is it
just matter of tastes?
The former takes the address of a nonexisting element. The
latter only uses pointer arithmetic.
&from[Nfrom] is, by definition, &(*(from + Nfrom)). And
that * operator in there results in undefined behavior.
I don't agree here.
Whether you agree or not, it's what the standard says.
As I understand it, it is the act of _accessing_ the first
element past the array to be undefined behavior,
Concerning unary *, the standard says that "result is an lvalue
referring to the object or function to which the expression
points." There must be an object or function there, or you have
undefined behavior.
In this regard, the standard bases itself on C90. In C90, the
question was actually raised, and answered by the C
committee---it is undefined behavior. The authors of the C
standard didn't like this, so in C99, they introduced a special
case:
The unary & operator returns the address of its operand.
If the operand has type ‘‘type’’, the result has type
‘‘pointer to type’’. If the operand is the result of a
unary * operator, neither that operator nor the &
operator is evaluated and the result is as if both were
omitted, except that the constraints on the operators
still apply and the result is not an lvalue. Similarly,
if the operand is the result of a [] operator, neither
the & operator nor the unary * that is implied by the []
is evaluated and the result is as if the & operator were
removed and the [] operator were changed to a +
operator. Otherwise, the result is a pointer to the
object or function designated by its operand.
The special case is present because such an expression would
otherwise be undefined behavior---C++ doesn't have this special
case.
You're point is, however, interesting. I don't know why the C
committee took this route, rather than simply stating that it is
only undefined behavior if there is an lvalue to rvalue
conversion or an attempt to modify the object through the
lvalue. Off hand, that would seem to me to be a simpler and
more general solution.
not the act of composing, getting or passing its address in
any manner.
Stroustrup does this in his example code...
int v[] = { 1, 2, 3, 4};
int* p3 = &v[4];
...and I wasn't able to find any clause of the standard giving
a different behavior or different requisites of behavior to
the process of creating an address using unary *, unary & and
the subscript operator.
The standard very clearly says that v[4] is the exact equivalent
of *(v + 4). Period. Unlike the C standard, it doesn't make
any exceptions. The standard also says that the result of a
unary * _must_ designate an object, and in this case, there is
no object at v+4, so the expression is undefined behavior.
FWIW, this fact wasn't recognized when the C standard was
originally adopted, which means that it wasn't realized when
much of the C++ standard was being written (and perhaps when
Stroustrup wrote the text you site). Once the problem was
pointed out, the C committee, in a response to a DR or in a
request for interpretation, recognized that as the standard
stood, it was undefined behavior---by that time, they were
already in the process of creating C99, so they added the
special text to remove the undefined behavior. I seem to
remember a little bit of discussion in the C++ committee as to
whether C++ should take the same steps, but in the end, it
didn't. (One of the arguments, IIRC, was that programmers
shouldn't use this form anyway, since in something like:
std::vector< int > v( 4 ) ;
int* p3 = &v[ 4 ] ;
it is also undefined behavior, and in a checking implementation,
will cause a fatal error. And I think it's impossible to
implement a checking implementation where this wouldn't be the
case; vector<>:perator[] would have to return a proxy which
overloaded operator&... and also operator. .)