Почему программа не падала, когда время жизни закончилось?

Учитывая приведенный ниже код, он выдаст предупреждение:

предупреждение: временная привязка к 'Foo::b' сохраняется только до выхода из конструктора [-Wextra]

struct Bar {
    inline void print() const { std::cout << "Bar" << std::endl; }
};

struct Foo {
    Foo() : b{} {}                    // create temporary
    void print() const { b.print(); } // OK but I'm expecting a crash here
    Bar&& b;
};

Foo f;     // Expecting lifetime of temporary ends here
f.print(); // OK - prints "Bar"

Я ожидаю, что доступ к Bar::print() через Foo::b приведет к сбою после выхода из конструктора Foo.

Почему программа до сих пор вызывает Bar::print() без сбоя?


person Joseph D.    schedule 25.04.2018    source источник
comment
Это неопределенное поведение. Это даже может означать, что это работает или кажется, что работает.   -  person Scheff's Cat    schedule 25.04.2018
comment
Вы только что доказали фактами, что undefined может быть неожиданным.   -  person bipll    schedule 25.04.2018
comment
является ли Bar&& b; висячим указателем?   -  person Joseph D.    schedule 25.04.2018
comment
Согласно SO: оператор двойного адреса С++? (&&) оборванная ссылка на значение rvalue. ;-)   -  person Scheff's Cat    schedule 25.04.2018
comment
@Scheff Однако ссылки не могут быть нулевыми, верно? почему он может болтаться?   -  person Joseph D.    schedule 25.04.2018
comment
Поскольку Bar не является полиморфным и не имеет элементов данных, ссылка не на что указывает, оборванная или нет. Почему компилятор должен создавать различие между действительной ссылкой на ничто и оборванной ссылкой на ничто? Он не обязан создавать сбой только потому, что мог.   -  person TrentP    schedule 25.04.2018
comment
@TrentP, не могли бы вы отослать меня к той части спецификаций, в которой это указано?   -  person Joseph D.    schedule 25.04.2018
comment
@codekaizer - этот вопрос обсуждался снова и снова на SO. Изменение указателя на ссылку и удержание разницы между ними не делает это совершенно новым вопросом. На это ответили смертью.   -  person StoryTeller - Unslander Monica    schedule 25.04.2018
comment
Я напоминал ваш образец в VS2013, зная, что любой уничтоженный экземпляр заполнен тестовыми шаблонами. К моему удивлению, я получил аналогичные предупреждения, и в моем случае это тоже сработало без сбоев. Итак, со второго взгляда я понял, что Bar::print() не имеет доступа ни к одному члену. При всем том, это неопределенное поведение.   -  person Scheff's Cat    schedule 25.04.2018
comment
Висячую ссылку очень легко создать: int *p = nullptr, &r = *p; r является ссылкой на... (как мне это назвать?) ...несуществующий экземпляр.   -  person Scheff's Cat    schedule 25.04.2018
comment
@StoryTeller, я понимаю. Я только что столкнулся с этой оборванной ссылкой на rvalue сегодня. не настаивая на том, что это новый вопрос. просто ищу разъяснений.   -  person Joseph D.    schedule 25.04.2018
comment
В конечном счете, да ссылка может болтаться. В более общем случае любое выражение glvalue может в конечном итоге не ссылаться на допустимый объект из-за человеческой ошибки. Как только это произойдет, у вас будет из чего выбирать.   -  person StoryTeller - Unslander Monica    schedule 25.04.2018
comment
@StoryTeller, спасибо. Итак, основываясь на вашем заявлении, можно ли с уверенностью сказать, что ссылки тоже могут быть нулевыми?   -  person Joseph D.    schedule 25.04.2018
comment
ИМХО, ссылка должна предоставлять живой объект (в отличие от указателя, который может быть преднамеренно nullptr). Но это может произойти так же, как и деление на 0 (что, вероятно, редко делается намеренно).   -  person Scheff's Cat    schedule 25.04.2018
comment
Да и нет. Формально ссылки не являются указателями и должны быть инициализированы идентификатором объекта. Но... как показывает Шефф, вы можете сломать его, введя UB в другом месте (скажем, с нулевым указателем).   -  person StoryTeller - Unslander Monica    schedule 25.04.2018
comment
@StoryTeller, Шефф, спасибо. добавил знания на сегодня.   -  person Joseph D.    schedule 25.04.2018
comment
@codekaizer, что класс без элементов данных и виртуальных методов не будет иметь связанных с ним данных? Если бы у него были данные, то что бы это было? Хотя ваш код вызывает неопределенное поведение, компиляторы не производят свой вывод случайным образом. Нет оснований ожидать, что висячая ссылка на ничто приведет к сбою, если отсутствует параметр отладки, специально предназначенный для обнаружения таких вещей. Что именно создается с помощью объекта, не указано, но что-то вроде §9.5.1 о том, что может быть в классе в объединении, дает представление о том, что ожидается от компилятора.   -  person TrentP    schedule 25.04.2018
comment
@TrentP - Поскольку Bar не полиморфен, если он полиморфен, имеет ли это значение?   -  person Joseph D.    schedule 25.04.2018
comment
@codekaizer, да. Полиморфный класс будет иметь своего рода указатель на таблицу указателей на функции, чтобы позволить компилятору знать, какие виртуальные методы вызывать из указателя базового класса. Вот почему в правиле объединения нет полиморфных классов. Если бы Bar::print() был виртуальным методом, можно было бы создать код, который, скорее всего, вызвал бы сбой при вызове висячей ссылки.   -  person TrentP    schedule 25.04.2018
comment
@TrentP, это что-то. спасибо!   -  person Joseph D.    schedule 25.04.2018