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.

Community
  • 1
  • 1
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 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. – Oliver Charlesworth Feb 28 '12 at 20:59
  • So the question is: "What is the reference saying you can't dereference a NULL pointer?" – Mooing Duck Feb 28 '12 at 21:00
  • @MooingDuck no. I'm looking for the reference that says `a->x` is equivalent to `(*a).x`. – Luchian Grigore Feb 28 '12 at 21:01
  • 1
    Related: http://stackoverflow.com/questions/5248877/accessing-static-member-through-invalid-pointer-guaranteed-to-work – Lightness Races in Orbit Feb 28 '12 at 21:02
  • @Joe That's what I said. I'm looking for the standard quote that says the part about the "syntactic sugar". – Luchian Grigore Feb 28 '12 at 21:02
  • This previously answered question may help a lot: http://stackoverflow.com/questions/669742/accessing-class-members-on-a-null-pointer – Sid Feb 28 '12 at 21:03
  • 1
    An extensive discussion of this topic is given [in this post][1]. [1]: http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-beha – Scott C Wilson Feb 28 '12 at 21:04
  • @Scott: Please join me in dup-voting. – Lightness Races in Orbit Feb 28 '12 at 21:07
  • @LuchianGrigore Yeah figured, look at the update on my answer, includes a link to a good post with a discussion on this topic – Sid Feb 28 '12 at 21:15
  • THis post has a detailed analysis of the topic: http://stackoverflow.com/questions/669742/accessing-class-members-on-a-null-pointer – Sid Feb 28 '12 at 21:01

4 Answers4

9

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?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 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. http://stackoverflow.com/questions/2727834/c-standard-dereferencing-null-pointer-to-get-a-reference –  Feb 28 '12 at 21:08
  • @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. – Lightness Races in Orbit Feb 28 '12 at 21:12
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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 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. – Luchian Grigore Feb 28 '12 at 21:03
  • 1
    @LuchianGrigore, it's a good question. The implementation of `GetSafeHwnd` has always made me a little nervous, even though I understand why it works. – Mark Ransom Feb 28 '12 at 21:08
0

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

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 3
    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. – Luchian Grigore Feb 28 '12 at 21:00
  • @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. – Ed S. Feb 28 '12 at 21:08
  • 1
    There are some free drafts lying around, not much different than the official version. – Luchian Grigore Feb 28 '12 at 21:10
  • @LuchianGrigore: Ok, I should grab one. I forget that the drafts are actually free. – Ed S. Feb 28 '12 at 21:11
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.