Захват недавно построенного объекта с помощью const ref undefined поведением


11

Хорошо ли следующее (надуманный пример) или это неопределенное поведение:

// undefined behavior?
const auto& c = SomeClass{};

// use c in code later
const auto& v = c.GetSomeVariable();

Ответы:


12

Это безопасно. Const ref продлевает временный срок службы. Объем будет являться областью действия конт.

Время жизни временного объекта может быть увеличено путем привязки к ссылке на постоянное значение или к ссылке на значение (начиная с C ++ 11), подробности см. В разделе инициализация ссылки .

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

  • временная привязка к возвращаемому значению функции в операторе возврата не расширяется: она уничтожается сразу в конце выражения возврата. Такая функция всегда возвращает висячую ссылку.
  • временная привязка к элементу ссылки в списке инициализатора конструктора сохраняется только до выхода из конструктора, а не до тех пор, пока объект существует. (примечание: такая инициализация некорректна по состоянию на DR 1696).
  • временная привязка к параметру ссылки в вызове функции существует до конца полного выражения, содержащего этот вызов функции: если функция возвращает ссылку, которая переживает полное выражение, она становится висячей ссылкой.
  • временная привязка к ссылке в инициализаторе, используемом в новом выражении, существует до конца полного выражения, содержащего это новое выражение, не дольше, чем инициализированный объект. Если инициализированный объект переживает полное выражение, его элемент ссылки становится висячей ссылкой.
  • временная привязка к ссылке в элементе ссылки агрегата, инициализированного с использованием синтаксиса прямой инициализации (скобки), в отличие от синтаксиса инициализации списка (фигурные скобки), существует до конца полного выражения, содержащего инициализатор. struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference

В общем, время жизни временного объекта не может быть дополнительно увеличено путем «передачи его»: вторая ссылка, инициализированная из ссылки, к которой привязан временный объект, не влияет на его время жизни.

как заметил @Konrad Rudolph (и см. последний абзац выше):

«Если c.GetSomeVariable()возвращается ссылка на локальный объект или ссылка на то, что он сам продлевает время жизни какого-либо объекта, расширение времени жизни не срабатывает»


1
Вы должны указать источник этой цитаты.
Гонки

@LightnessRaceswithMonica сделано. Я искал лучший текст.
Забвение

2
Было бы хорошо подчеркнуть, что это верно только для ценностей . Если c.GetSomeVariable()возвращает ссылки на локальный объект или ссылка , что оно само продление срока эксплуатации какого - то объекта, увеличение срока эксплуатации никак не загнуться.
Konrad Rudolph

@KonradRudolph Спасибо! Я добавил исключение тоже.
Забвение


3

Да, это совершенно безопасно: привязка к constссылке продлевает время существования временного объекта до объема этой ссылки.

Обратите внимание, что поведение не является транзитивным, хотя. Например, с

const auto& cc = []{
    const auto& c = SomeClass{};
    return c;
}();

cc болтается.


2

Это безопасно.

[class.temporary]/5: Есть три контекста, в которых временные объекты уничтожаются в другой точке, чем конец полного выражения . [..]

[class.temporary]/6Третий контекст - это когда ссылка связана с временным объектом. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени жизни ссылки, если значение glvalue, к которому привязана ссылка, было получено с помощью одного из следующих : [здесь много всего]


1

Это безопасно в этом конкретном случае. Однако обратите внимание, что не все временные данные безопасны для захвата по константной ссылке ... например

#include <stdio.h>

struct Foo {
    int member;

    Foo() : member(0) {
        printf("Constructor\n");
    }

    ~Foo() {
        printf("Destructor\n");
    }

    const Foo& method() const {
        return *this;
    }
};

int main() {
    {
        const Foo& x = Foo{};        // safe
        printf("here!\n");
    }
    {
        const int& y = Foo{}.member; // safe too (special rule for this)
        printf("here (2)!\n");
    }
    {
        const Foo& z = Foo{}.method(); // NOT safe
        printf("here (3)!\n");
    }
    return 0;
}

Полученная ссылка zНЕ является безопасной для использования, поскольку временный экземпляр будет уничтожен в конце полного выражения до достижения printfоператора. Выход:

Constructor
here!
Destructor
Constructor
here (2)!
Destructor
Constructor
Destructor
here (3)!
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.