Let's assume we have a class B that has a member which is default initialized to 42. This class knows how to print the value of its member (it does so in the constructor):
struct B
{
  B() : member(42) { printMember(); }
  void printMember() const { std::cout << "value: " << member << std::endl; }
  int member;
};
Then we add a class A which receives a const reference to a B and asks B to print its value:
struct A
{
  A(const B& b) { b.printMember(); }
};
Finally we add another class Aggregate that aggregates an A and a B. The tricky part is that object a of type A is declared before object b type B, but then a is initialized using a (not yet valid?) reference to b:
struct Aggregate
{
  A a;
  B b;
  Aggregate() : a(b) { }
};
Consider the output of creating an Aggregate (I have added some logging to both the constructor and destructor of A and B) (Try it online!):
a c'tor
value: 0
b c'tor
value: 42
b d'tor
a d'tor
Am I right to assume that it is invalid to initialize a with a reference to a (not yet valid) instance of b and that this is therefore undefined behavior?
I am aware of the initialization order. This is what makes me struggle. I know that b is not yet constructed, but I also think to know that b's future address can be determined even before b is constructed. Therefore I assumed there could be some rule that I am not aware of that allows the compiler to default initialize bs members prior to b's construction or something like that. (It would have been more obvious if the first printed out value would have been something that looks random rather than 0 (the default value of int)).
This answer helped me understand that I need to distinguish between
- binding a reference to an uninitialized object (which is valid) and
- accessing by reference an uninitialized object (which is undefined)
 
     
     
    