С++ - использование константной ссылки для продления члена временного, нормально или UB?

рассмотрим что-то вроде этого:

#include <iostream>

struct C {
    C(double x=0, double y=0): x(x) , y(y) {
        std::cout << "C ctor " << x << " " <<y << " "  << "\n";
    }
    double x, y;
};

struct B {
    B(double x=0, double y=0): x(x), y(y) {}
    double x, y;
};

struct A {
    B b[12];

    A() {
        b[2] = B(2.5, 14);
        b[4] = B(56.32,11.99);
    }
};


int main() {
    const B& b = A().b[4];
    C c(b.x, b.y);
}

когда я компилирую с -O0, я получаю печать

C ctor 56.32 11.99

но когда я компилирую с -O2, я получаю

 C ctor 0 0

Я знаю, что мы можем использовать константную ссылку для продления локального временного, так что-то вроде

const A& a = A();
const B& b = a.b;

было бы совершенно законно. но я изо всех сил пытаюсь найти причину, почему один и тот же механизм/правило не применяется для каких-либо временных

ОБНОВЛЕНИЕ ДЛЯ БУДУЩЕЙ ССЫЛКИ:

Я использую GCC версии 6.3.0

Ответы

Ответ 1

Ваш код должен быть правильно сформирован, потому что для временных

(выделение мое)

Всякий раз, когда ссылка связана с временным объектом или с его подобъектом, срок действия временного элемента увеличивается, чтобы соответствовать времени жизни ссылки

.Учитывая A().b[4], b[4] является подобъектом b, а элемент данных b является подобъектом временного массива A(), время жизни которого должно быть увеличено.

LIVE на Clang10 с -O2
LIVE на gcc10 с -O2

Кстати, это похоже на gcc ошибку, которая была исправлена.

Из стандарта [класс.время]/6

Третий контекст - это когда ссылка связана с временным объектом. 36 Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования объекта. ссылка, если glvalue, к которому привязана ссылка, была получена одним из следующих способов:

...

[ Example:

template<typename T> using id = T;

int i = 1;
int&& a = id<int[3]>{1, 2, 3}[i];          // temporary array has same lifetime as a
const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b
int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0);
                                           // exactly one of the two temporaries is lifetime-extended

— end example ]

Ответ 2

A(). B [4] не является temp или rvalue, поэтому не работает. Хотя A() является временным, вы создаете ссылку на элемент массива, который существует в точке создания. Затем dtor запускает A(), что означает, что последующий доступ к b.b становится несколько неопределенным поведением. Вы должны держаться за A & чтобы убедиться, что б остается в силе.

    const A& a = A();
    const B& b = a.b[4];
    C c(b.x, b.y);