8

Possible Duplicate:
When does invoking a member function on a null instance result in undefined behavior?
C++ standard: dereferencing NULL pointer to get a reference?

Say I have the class:

class A
{
public:
   void foo() { cout << "foo"; }
};

and call foo like so:

A* a = NULL;
a->foo();

I suspect this invokes undefined behavior, since it's equivalent to (*a).foo() (or is it?), and dereferencing a NULL is UB, but I can't find the reference. Can anyone help me out? Or is it defined?

No, the function is not virtual. No, I'm not accessing any members.

EDIT: I voted to close this question but will not delete it as I couldn't find the duplicate myself, and I suspect this title might be easier to find by others.

10
  • I don't think there's anything in the standard that restricts, for example, implementing all member functions via vtable lookup. So in such an implementation, you really would be dereferencing NULL (rather than just statically binding to a::foo). I can't provide a standard quote, though. Commented Feb 28, 2012 at 20:59
  • So the question is: "What is the reference saying you can't dereference a NULL pointer?" Commented Feb 28, 2012 at 21:00
  • THis post has a detailed analysis of the topic: stackoverflow.com/questions/669742/… Commented Feb 28, 2012 at 21:01
  • 1
    Related: stackoverflow.com/questions/5248877/… Commented Feb 28, 2012 at 21:02
  • 1
    An extensive discussion of this topic is given [in this post][1]. [1]: stackoverflow.com/questions/2474018/… Commented Feb 28, 2012 at 21:04

4 Answers 4

10

I'm looking for the reference that says a->x is equivalent to (*a).x.

Here it is:

[C++11: 5.2.5/2]: For the first option (dot) the first expression shall have complete class type. For the second option (arrow) the first expression shall have pointer to complete class type. The expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder of 5.2.5 will address only the first option (dot). In either case, the id-expression shall name a member of the class or of one of its base classes. [ Note: because the name of a class is inserted in its class scope (Clause 9), the name of a class is also considered a nested member of that class. —end note ] [ Note: 3.4.5 describes how names are looked up after the . and -> operators. —end note ]

There is no direct quotation for dereferencing a NULL pointer being UB, unfortunately. You may find more under this question: When does invoking a member function on a null instance result in undefined behavior?

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

2 Comments

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. stackoverflow.com/questions/2727834/…
@0A0D: That's non-normative. GMan explores the topic in more detail in the post I linked to, including quoting that same non-normative passage that you posted in your comment, but going further with some balanced reasoning. I suggest reading it.
1

I'm aware of at least one case where this idiom is not only allowed but relied upon: Microsoft's MFC class CWnd provides a member function GetSafeHwnd which tests if this==NULL and returns without accessing any member variables.

Of course there are plenty of people who would claim that MFC is a very bad example.

Regardless of whether the behavior is undefined or not, in practice it's not likely to behave badly. The compiler will treat a->foo() as A::foo(a) which does not do a dereference at the call site, as long as foo is not virtual.

2 Comments

That's the exact reason I'm asking. I saw this in production code, I'm assuming it's UB, but I also want to prove it.
@LuchianGrigore, it's a good question. The implementation of GetSafeHwnd has always made me a little nervous, even though I understand why it works.
0

Yes, that is UB as a has not been initialized to point to a valid memory location before it is dereferenced.

4 Comments

I'm looking for a quote from the standard. Your answer provides no additional information than I already stated in the question. PS I did not downvote.
@LuchianGrigore: Well it's pretty common knowledge that this is UB, but the standard isn't free and I don't have it lying around.
There are some free drafts lying around, not much different than the official version.
@LuchianGrigore: Ok, I should grab one. I forget that the drafts are actually free.
0

It is covered here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

At least a couple of places in the IS state that indirection through a null pointer produces undefined behavior: 1.9 [intro.execution] paragraph 4 gives "dereferencing the null pointer" as an example of undefined behavior, and 8.3.2 [dcl.ref] paragraph 4 (in a note) uses this supposedly undefined behavior as justification for the nonexistence of "null references."

However, 5.3.1 [expr.unary.op] paragraph 1, which describes the unary "*" operator, does not say that the behavior is undefined if the operand is a null pointer, as one might expect. Furthermore, at least one passage gives dereferencing a null pointer well-defined behavior: 5.2.8 [expr.typeid] paragraph 2 says

If the lvalue expression is obtained by applying the unary * operator to a pointer and the pointer is a null pointer value (4.10 [conv.ptr]), the typeid expression throws the bad_typeid exception (18.7.3 [bad.typeid]).

This is inconsistent and should be cleaned up.

Read more at the link if you want to learn more.

3 Comments

This is a good quote and very pertinent. However, that hardly "covers" it; it merely agrees that this is a question to be answered; it does not answer it in itself.
@LightnessRacesinOrbit: I'm not going to plagiarize the whole page.
If you did it wouldn't change anything. Open issues are not specifications.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.