6

Inside a constructor, calling non-virtual member functions is permitted.

Does from this fact follow that the following piece of code is well-defined?

struct A {
    void foo { std::cout << "Hi there! My address is: " << this; }
};

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

Answer?

With the help of some links given in the comments, and the links given in the linked pages, I now think that the answer can be found e.g. in

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3035.pdf

§3.8 par. 5, p. 66:

"Before the lifetime of an object has started but after the storage which the object will occupy has been allocated ... [t]he program has undefined behavior if [...] the pointer is used to access a non-static data member or call a non-static member function of the object"

Then it should be even more undefined to call a member function if storage has not been allocated at all.

I guess one important reason why it is a good idea to make it undefined is explained here: https://stackoverflow.com/a/3257755/1419315

Community
  • 1
  • 1
JohnB
  • 13,315
  • 4
  • 38
  • 65
  • 2
    http://stackoverflow.com/questions/2533476/what-will-happen-when-i-call-a-member-function-on-a-null-object-pointer?rq=1 – DCoder Dec 29 '13 at 20:47

1 Answers1

4

That code is undefined behavior.

Note that inside the constructor you can also call virtual member function.

The somewhat tricky part is calling virtual member function during member initialization before the constructor code begins. Still valid but it's not obvious what happens (the point is that until the constructor code begins the object isn't considered yet an instance of its class and virtual member functions get dispatched to the base class).

Some compilers emit a warning if you use this in the member initialization list exactly because the this pointer will behave strangely at that point (it will start behave normally only after the start of the constructor).

The code apparently works because most compilers use the VMT approach for method dispatching but the VMT is not needed to call a non-virtual method and thus if the method code doesn't dereference in any way this then things seems to "work". However the fact that the code seems to work in an implementation (or even in every implementation for that matter) still doesn't make it legal C++ code.

6502
  • 112,025
  • 15
  • 165
  • 265
  • As far I know, you shouldn't call a virtual method inside the ctor. – Manu343726 Dec 29 '13 at 20:49
  • @Manu343726 Only because it probably won't do what you want. If it does do what you want, there's nothing wrong with it, it's valid in standard C++. –  Dec 29 '13 at 20:51
  • @hvd oh, because if you have a class hierarchy, you instance an object of a derived class (Which constructor calls to the base class constructor first) and in the base class ctor you call a virtual function? – Manu343726 Dec 29 '13 at 20:54
  • @hvd what I don't understand completely is: Is not the vptr of the object initialized before the execution of any ctor and bases ctors? If that was true, there would no problem with virtual calls in base ctors. – Manu343726 Dec 29 '13 at 20:56
  • @Manu343726 You're worrying too much about implementation details, IMO. Conceptually, it's simpler. Given `struct S2 : S`, constructing `S2` first creates an `S` subobject, and only then the full `S2`. During the construction of the `S` subobject, there is no `S2` object, and if you have no `S2` object, you cannot call `S2`'s methods, so virtual method calls have nothing else to call but `S`'s implementation. If that's what you want to call, then nothing wrong with doing so. But yes, your idea of how object construction is implemented is how it works in some other environments/languages. –  Dec 29 '13 at 21:03
  • @hvd I understand the concept perfectly, I was asking about how it really works and how it really performs :) – Manu343726 Dec 29 '13 at 21:04
  • @Manu343726 Ah, okay. :) In that case... Of course, this is system dependent, but if the base class constructor sets the vtable pointer, and then starts calling virtual functions before the derived class constructor is back in control, there's no way the derived class constructor can redirect those functions to its own implementation, unless it can indicate somehow that the base class constructor should leave the vtable pointer alone, and C++ just doesn't have such a way. (This isn't the point of either the question or this answer, so perhaps we should drop it.) –  Dec 29 '13 at 21:13