43

I'm wondering about what the C++ standard says about code like this:

int* ptr = NULL;
int& ref = *ptr;
int* ptr2 = &ref;

In practice the result is that ptr2 is NULL but I'm wondering, is this just an implementation detail or is this well defined in the standard?
Under different circumstances a dereferencing of a NULL pointer should result in a crash but here I'm dereferencing it to get a reference which is implemented by the compiler as a pointer so there's really no actual dereferencing of NULL.

2

5 Answers 5

55

Dereferencing a NULL pointer is undefined behavior.

In fact the standard calls this exact situation out in a note (8.3.2/4 "References"):

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 an aside: The one time I'm aware of that a NULL pointer can be "dereferenced" in a well-defined way is as the operand to the sizeof operator, because the operand to sizeof isn't actually evaluated (so the dereference never actually occurs).

Sign up to request clarification or add additional context in comments.

5 Comments

And indeed if it's an operand of typeid and if it's a null pointer of type PolymorphClass*, then it's dereferenced and evaluated. Still it's well-defined (throwing bad_typeid). I do really not like that special typeid treatment.
It's unfortunate about not allowing a NULL reference. It exhibits some cool properties, but I guess it just complicates code. :( If preconditions were available and code could be better verified, NULL references could be used safely.
sizeof() is an operator on the type of a variable, not the value. NULL pointers do have types.
@jforberg: I don't see anyone here claiming otherwise?
@Lightness No-one is. I'm just clarifying.
5

Dereferencing a NULL pointer is explicitly undefined behaviour in the C++ standard, so what you see is implementation specific.

Copying from 1.9.4 in the C++0x draft standard (similar to previous standards in this respect):

Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. - end note]

4 Comments

It's funny, because nobody has been able to show where in the standard dereferencing a null pointer is explicitly made UB. The standard is incorrect here.
@curiousguy: 8.3.2.5 once again alludes to the fact that dereferencing a null pointer is undefined. But you are right, it does so as if it was explained elsewhere. Anyway, 1.3.13 explains that any behaviour that is not explicitly defined is considered undefined, so this can be the case.
"8.3.2.5" BTW, it's spelled 8.3.2/5. There is no 8.3.2.5 section. "any behaviour that is not explicitly defined is considered undefined" You are right: dereferencing a pointer is only defined if the pointer points to an object. But it would be slightly more clear if the standard was explicit about that - and less electronic ink would be spent on this non-issue.
Notes are non-normative. This note was in fact removed as the result of DR 1102 with the stated reasoning being that it was not undefined behaviour to dereference a null pointer.
1

Dereferencing a NULL pointer is undefined behaviour. You should check if a value is NULL before dereferencing it.

Comments

1

For completeness, this: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 talks specifically about this issue.

4 Comments

Hum... very creative thinking. So, calling a member function with a null this is allowed!!! I wonder what they were smoking. Anyway, 7 years latter nothing has been done in the direction of this craziness.
Actually it isn't, according to stackoverflow.com/a/2474021/399317 (because of lvalue-to-rvalue conversion)
Interesting that the #232 uses division by zero as an example of UB, when many C++ implementations implicitly incorporate IEEE-754, which defines the effects of division by positive and negative zero. Integer division by zero is UB, but the example doesn't specify that.
That you have to use the word "many" is an example of UB.
-2
int& ref = *ptr;

The above statement doesn't actually dereference anything. So there's no problem until you use the ref (which is invalid).

6 Comments

Nonsense. unary * is actually the dereference operator. It actually performs the dereference operation.
@curiousguy: I advise you to compile this and see the code in the disassembler. The reference ref is essentially a pointer, so the above statement is just a pointer assignment behind the scenes.
You misunderstand me. I do not care what assembly code is generated. What is *ptr, according you?
@curiousguy: *ptr is a dereferencing indeed. But this doesn't mean that it is actually done (evaluated). For instance, you can write sizeof(*ptr) and the expression *ptr is guaranteed not to be evaluated during run-time.
Indeed, the operand of sizeof is not evaluated: you may write sizeof(1./0.) without any problem. That's because sizeof is only concerned about the type of its operand. OTOH, the operand of & is evaluated, otherwise what would address-of apply to?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.