Предположим, у нас есть класс 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
)).
Этот ответ помог мне понять, что мне нужно различать
- привязка ссылки к неинициализированному объекту (который действителен) и
- доступ по ссылке к неинициализированному объекту (который не определен)