Предположим, у нас есть класс B, у которого есть member который по умолчанию инициализирован в 42. Этот класс знает, как напечатать значение своего member (он делает это в конструкторе):
struct B
{
B() : member(42) { printMember(); }
void printMember() const { std::cout << "value: " << member << std::endl; }
int member;
};
Затем мы добавляем класс A который получает константную ссылку на B и просит B напечатать его значение:
struct A
{
A(const B& b) { b.printMember(); }
};
Наконец, мы добавляем еще один класс Aggregate который агрегирует A и B Сложная часть является то, что объект типа a A объявляется перед тем объектом b типа B, а затем инициализируется с использованием (еще не действительная?) Ссылки на a b:
struct Aggregate
{
A a;
B b;
Aggregate() : a(b) { }
};
Рассмотрим результат создания Aggregate (я добавил некоторые записи как в конструктор, так и в деструктор A и B) (попробуйте онлайн!):
a c'tor
value: 0
b c'tor
value: 42
b d'tor
a d'tor
Правильно ли я предполагаю, что неверно инициализировать a ссылкой на (еще не действительный) экземпляр b и что поэтому это неопределенное поведение?
Я в курсе порядка инициализации. Это то, что заставляет меня бороться. Я знаю, что b еще не сконструирован, но я также думаю, что знаю, что b будущий адрес может быть определен еще до того, как b сконструирован. Поэтому я предположил, что может быть какое-то правило, о котором я не знаю, которое позволяет компилятору инициализировать b членов по умолчанию перед созданием b или что-то в этом роде. (Было бы более очевидно, если бы первое распечатанное значение было бы чем-то, что выглядит случайным, а не 0 (значение по умолчанию int)).
Этот ответ помог мне понять, что мне нужно различать
- привязка ссылки к неинициализированному объекту (который действителен) и
- доступ по ссылке к неинициализированному объекту (который не определен)