Подтвердить что ты не робот

Const ссылается на члена временного объекта

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

Пример:

#include <string>

std::pair<std::string, int> getPair(int n)
{
    return {std::to_string(n), n};
}

int main(int, char*[])
{
    const int x = 123456;
    const auto& str = getPair(x).first;
    printf("%d = %s\n", x, str.c_str());    
    return 0;
}

Вывод:

123456 = 123456
4b9b3361

Ответ 1

Да, этот код вполне приемлем. Правилами, согласно стандарту, являются ([class.temporary]):

  1. Существует два контекста, в которых временные разной точки, чем конец fullexpression. Первый контекст когда вызывается конструктор по умолчанию для инициализации элемента массив. Если конструктор имеет один или несколько аргументов по умолчанию, уничтожение каждого временного объекта, созданного в аргументе по умолчанию, упорядочивается перед построением следующего элемента массива, если таковой имеется.

  2. Второй контекст - это когда ссылка привязана к временному. временный, к которому привязана ссылка, или временная, которая является полный объект подобъекта, к которому привязана ссылкасохраняется на протяжении жизненного цикла ссылки...

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

Обратите внимание, что first имеет право быть подобъектом [intro.object]:

  1. Объекты могут содержать другие объекты, называемые подобъектами. Субобъект может быть субобъектом-членом (9.2), подобъектом базового класса (п. 10) или элемент массива. Объект, который не является подобъектом какого-либо другого объекта называется полным объектом.

Ответ 2

Он четко определен.

Из стандарта: $12.2/6 Временные объекты [class.temporary]:

(акцент мой)

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

И о субобъекте, $1.8/2 Объектная модель С++ [intro.object]:

(акцент мой)

Объекты могут содержать другие объекты, называемые подобъектами. Субобъект может быть субобъектом ([class.mem]), подобъектом базового класса (пункт [class.derived]) или элемент массива. Объект, который не является подобъектом какого-либо другого объекта, называется полным объектом.

first привязан к ссылке, и это субобъект элемента std::pair, поэтому временное время жизни std::pair (т.е. полный объект) будет продлено, код должен быть точным.

Только для справки: Clang и GCC сказать да, VC говорит нет.

Ответ 3

Как я упоминал в своем комментарии:

Продолжительность временного пребывания должна быть увеличена до тех пор, пока время жизни его членского доступа (str в этом случае). Тем не менее, вы должно быть просто в порядке, взяв возвращаемое значение с помощью копии. RVO избежит делать дополнительные копии.

Из стандарта, раздел 12.2.5:

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

- временная привязка к ссылочному элементу в конструкторах ctor-initializer (12.6.2) сохраняется до выхода конструктора.

- Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения содержащий вызов.

Чтобы избавиться от каких-либо проблем, я бы предпочел:

auto m_p = getPair(x);

Это так же эффективно, как и в случае RVO, которое должен выполнять каждый компилятор для этого случая.

Ответ 4

Это представляется в 12.2/4-5:

Существует два контекста, в которых временные другой точки, чем конец полного выражения. Первый контекст... [материал, относящийся к массивам]

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

Существует четыре исключения, касающиеся связывания конструктора ссылочных элементов, вызовов функций, возвращаемых по ссылке функций и ссылок, связанных в новых инициализаторах.

Ни один из этих случаев не применяется, поэтому временное уничтожается в конце полного оператора, оставляя оборванную ссылку на члена временного.

Просто помогите компилятору понять, что он может перемещаться из временного: const auto str = std::move(getPair(x).first);