Захват недавно построенного объекта с помощью const ref undefined поведением - PullRequest
9 голосов
/ 31 октября 2019

Нормально ли следующее (надуманный пример) поведение или неопределенное поведение:

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

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

Ответы [ 5 ]

11 голосов
/ 31 октября 2019

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

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

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

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

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

как указано @ Конрад Рудольф (и см. последний абзац выше):

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

4 голосов
/ 31 октября 2019

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

3 голосов
/ 31 октября 2019

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

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

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

cc dangles.

2 голосов
/ 31 октября 2019

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

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

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

1 голос
/ 31 октября 2019

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

#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)!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...