Is this C++ member initialization behavior well defined?

Yes, you are right that it is UB, but for different reasons than just storing a reference to an object that hasn't been constructed.

Construction of class members happens in order of their appearance in the class. Although the address of B is not going to change and technically you can store a reference to it, as @StoryTeller pointed out, calling b.printMember() in the constructor with b that hasn't been constructed yet is definitely UB.


The order of initialization of class members is as below.

From CPP standard (N4713), the relevant portion is highlighted:

15.6.2 Initializing bases and members [class.base.init] ...
13 In a non-delegating constructor, initialization proceeds in the following order:
(13.1) — First, and only for the constructor of the most derived class (6.6.2), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
(13.3) — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
(13.4) — Finally, the compound-statement of the constructor body is executed.
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note ]