23
votes

Consider:

int* ptr = (int*)0xDEADBEEF;
cout << (void*)&*ptr;

How illegal is the *, given that it's used in conjunction with an immediate & and given that there are no overloaded op&/op* in play?


(This has particular ramifications for addressing a past-the-end array element &myArray[n], an expression which is explicitly equivalent to &*(myArray+n). This Q&A addresses the wider case but I don't feel that it ever really satisfied the above question.)

3
A good compiler should convert the effect of &*ptr to ptr; so practically ok. But theoretically it can be an undefined behavior.iammilind
I'm pretty sure we've had this argument before, and there seems to be some difference of opinion what the current standard implies even among those who've contributed to DRs and the like on the subject. The committee declined to introduce any form of non-existent lvalues to explicitly allow such tricks (so conservatively: it isn't allowed since lvalue expressions refer to an object, or some such wording, whereas *ptr is not an object), but no lvalue-to-rvalue conversion takes place on the non-existent referand (so optimistically: it'll work).Steve Jessop
I remember a comment by Stephan T Lavavej in one of his standard library tutorial videos from Channel 9 that saying &myArray[n] for an array of n elements is illegal, and you should instead be doing &myArray[0] + n. In other words, it is OK to walk a pointer beyond the end of an array, but it is illegal to dereference the pointer once it is beyond the bounds of the array.Praetorian
@Praetorian (and Kerrek): it's undefined behavior to even form the pointer value beyond the "one-past-the-end" address. For rationale, consider a hypothetical implementation where incrementing that address results in a trap representation of the pointer type, or overflows resulting in a hardware exception. Addresses aren't numbers in the C++ standard, even if they are in all known implementations: to the standard unallocated address space is a yawning void of chaos.Steve Jessop
For reference, in C (C99 at least), the standard says that &*E is equivalent to E; this is explicitly allowed. So the only problem that remains (in C) is whether creating an invalid pointer in the first place is undefined. I've never found the equivalent language in the C++ standards.Oliver Charlesworth

3 Answers

18
votes

According to the specification, the effect of dereferencing an invalid pointer itself produces undefined behaviour. It doesn't matter what you do after dereferencing it.

17
votes

Assuming the variable `ptr' does not contain a pointer to a valid object, the undefined behavior occurs if the program necessitates the lvalue-to-rvalue conversion of the expression `*ptr', as specified in [conv.lval] (ISO/IEC 14882:2011, page 82, 4.1 [#1]).

During the evaluation of `&*ptr' the program does not necessitate the lvalue-to-rvalue conversion of the subexpression `*ptr', according to [expr.unary.op] (ISO/IEC 14882:2011, page 109, 5.3.1 [#3])

Hence, it is legal.

2
votes

It is legal. Why wouldn't it be? You're just setting a value to a pointer, and then accessing to it. However, assigning the value by hand must be obviously specified as undefined behavior, but that's the most a general specification can say. Then, you use it in some embedded software controller, and it will give you the correct memory-mapped value for some device...