Увеличение продолжительности жизни, значения и значения
После хорошо принятого ответа на этот вопрос Допускают ли ссылки на rvalue висячие ссылки? Казалось бы, значения xvalue не продлеваются, когда они присваиваются rvalue-ссылке lvalue, как в вопросе. Однако, когда я делаю это
#include <iostream>
using namespace std;
class Something {
public:
Something() {
cout << "Something()" << endl;
}
Something(const Something&) {
cout << "Something(const Something&)" << endl;
}
Something(Something&&) {
cout << "Something(Something&&)" << endl;
}
~Something() {
cout << "~Something()" << endl;
}
int a;
};
Something make_something() {
return Something{};
}
int main() {
auto&& something = make_something().a;
return 0;
}
Время жизни объекта, возвращаемого вызовом make_something
продлен, хотя make_something().a
является значением xvalue согласно http://en.cppreference.com/w/cpp/language/value_category (в третьем пункте в объяснении xvalues перечислены права доступа к элементу, которые у меня есть выше, в качестве значения xvalue,)
am, член выражения объекта, где a является значением r, а m является нестатическим членом данных не ссылочного типа;
Если категории значений не определяют, когда время жизни значения r будет увеличено, то что тогда? Мне трудно понять, когда время жизни rvalue продлено в C++
2 ответа
Увеличение продолжительности жизни не заботит категории значений. Как сказано в [class.tevent]/p6:
Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки.
Акцент добавлен.
Здесь ничего не сказано о категории значений выражения, на которое делается ссылка.
То, что определяет, является ли временный объект расширенным, является точно вышеизложенным (и еще несколькими правилами).
Но это не объясняет, почему добавление
std::move()
вокруг временного, которому назначается ссылка, не продлевает срок службы
std::move
не магическая, определяемая компилятором конструкция в C++. Это вызов функции, и поэтому он ведет себя не иначе, как любой другой вызов функции C++.
Итак, если у вас есть std::move(Type())
, что это значит? Это значит, что вы создадите временную, привязав ее к параметруstd::move
, затем вызовите ту функцию, которая будет что-то возвращать.
Привязка временного к параметру функции, как указано в [class.teditional]/p6, означает, что время жизни временного объекта устанавливается равным времени жизни полного выражения, которое его создало (если не для этого правила, то временное будет должны быть уничтожены в конце вызова функции, так как это конец времени жизни ссылки).
Неважно, что функция делает, говорит или подразумевает. Неважно, может ли компилятор встроить что-либо и определить, что возвращаемое значение является ссылкой на аргумент, полученный из временного объекта. Время жизни этого временного фиксированного выражения, а не расширенного.
Если категории значений не определяют, когда время жизни значения r будет увеличено, то что тогда? Мне трудно понять, когда время жизни rvalue продлено в C++
Обратите внимание, что категории значений описывают выражения, а не объекты. Категории значений (xvalue, prvalue или что-либо еще) не будут расширяться каким-либо образом. Только объекты могут иметь жизнь.
Из стандартного чертежа n4296:
- §12.2.1
Временные объекты типа класса создаются в различных контекстах: привязка ссылки к prvalue (8.5.3), возвращение prvalue (6.6.3), преобразование, которое создает prvalue (4.1, 5.2.9, 5.2.11, 5.4), выбрасывая исключение (15.1), и в некоторых инициализациях (8.5).
а также
- §12.2.4
Есть два контекста, в которых временные уничтожаются в другой точке, чем конец полного выражения. [...]
Второй контекст, когда ссылка связана с временным. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки.
Примечание: я не цитировал первый контекст, так как он имеет незначительное отношение к вопросам. Курсив выделен мной.
Таким образом, категория значения выражения функции makesomething()
это prvalue
создание временного типа класса, согласно первому абзацу, указанному выше. makesomething().a
доступ к временному, полному подобъекту. Связывание этого временного объекта со ссылкой приводит, согласно второму контексту, указанному выше, к увеличению срока службы.
Время жизни подобъекта a
связан со временем жизни предыдущего созданного временного объекта, что делает его значением с истекающим сроком (xvalue). Без продления времени жизни путем привязки его к ссылке он будет уничтожен вместе с временным объектом класса. Таким образом, в этом случае после ;
,