#include <iostream>
using namespace std;
struct S{
~S() {cout << "destr\n";}
};
int main(){
S &&r = (S &&) S{};
// const S &r = (S &&) S{}; // аналогично
cout << "-------------\n";
}
Вообще я думал, что жизнь временных объектов продливается лишь единожды - при первой инициализации ссылки им, быстрый взгляд в справочник говорит о том же. А у нас здесь две инициализации ссылки, т.е. объекту стоило бы уничтожиться после двоеточия. Но запустив тест получается, что объект переживает cout, компилятор не ругается (clang, gcc). Вопрос - будет ли жить временный объект до тех пор, пока живёт r, вообще он живёт, но насколько это по правилам?
In general, the lifetime of a temporary cannot be further extended by «passing it on»: a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.
Ну это я читал, продливать жизнь можно лишь один раз - при первой привязки prvalue к ссылке. А про копирование ссылок сказано следующее:
In general, the lifetime of a temporary cannot be further extended by «passing it on»: a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
Вроде вопросов быть и не должно, но компиляторы ведь не ругаются.
ЗЫ: т.е. prvalue должен умереть после смерти (S &&)
И в неявной форме такое поведение используют повсеместно. Например можно мувать объекты из вектора. Не говоря уже о perfect forwarding-е где используется ровно эта же цепочка кастов.
ну там явное копирование ссылок, никакого продления быть не может. Даже если в возвращаемый тип функции ссылка и мы кидаем в return prvalue (временный объект), то продление его жизни так же не произойдёт
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
...
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
...
Example:
[...]
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
Так что всё нормально (см. после примера ещё notes).
Шестой пункт расписали подробно после C++17. Т.е. только в C++20 в стандарте появятся ясные правила, при какой форме инициализирующего выражения байндинг к ссылке продлевает lifetime временного объекта, создаваемого в этом выражении. См. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0727r0.html
Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue.
This property of an expression is called its value category.
А мне вот что интересно :-) Такие вопросы возникают из реальных задач вне локалхоста, или это просто поиск приключений? :-) Зачем лезть в эти закоулки цепепе? :-) Это для того, чтобы написать тарабарщину, которую потом кто-то другой будет вынужден читать с засаленным справочником, отыскивая в нём лайфтаймы этих крючков? :-) Почувствовать себя гением? :-) Лол :-)
Где тут две инициализации ссылки? Каст — это не инициализация ссылки.
А как можно выполнить такое вот выражение не создав две ссылки (без учёта всяких там оптимизаций компилятора)?
struct S{
S(int) {cout << "const\n";}
~S() {cout << "dest\n";}
};
int main(){
const S &r = (const S &)5;
}
У rvalue нет никакой жизни. rvalue — это такой подкласс выражений (привет, tailgunner). Время жизни бывает у объектов (и ссылок).
Ну просто к словам придираетесь. Когда говорят о value категориях выражений, то имеют в виду их «expression evaluation» - т.е. то, что останется после расчёта выражения. Выражением является и
any_defined_var; //lvalue
и
int{0}; //prvalue
а о выражениях говорят лишь для того, чтобы концепция охватывала и такую мешанину: val+val-val... . А в основе лежит - время жизни объектов. Формально вроде правы, предлагаете выражаться в подобном стиле: «Продление жизни expression evaluation of prvalue expression», ну и к чему эта педантичность?
Довольно кривой ответ. Хотя, может в 2015-м году он и соответствовал кривому wording-у в стандарте.
Первый ответ хотя бы указывает на правильный issue, только вот термин «temporary expression» не определили и точно не определят, а оставшиеся 2.5 места в стандарте, где употребляется это бессмысленное словосочетание, скоро наконец вычистят.
А вы тему читаете прежде чем ответы выдавать? Я и без стековерфлоу знал, что инициализация ссылки в return не продливает жизнь ни при каких условиях. Более того, писал выше об этом.
Я смотрю в http://eel.is/c draft/intro.execution#def:evaluation и мне кажется, что не это имеют в виду.
Не знаю как иначе это можно понять:
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category. Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories: prvalue, xvalue, lvalue, defined as follows:
*a glvalue (“generalized” lvalue) is an expression whose evaluation determines the identity of an object, bit-field, or function;
...
Я не могу понять, что ты хочешь сказать, но попробую ответить: когда говорят о value category имеют в виду value category, а когда говорят об expression evaluation имеют в виду expression evaluation.
Возможно кто-то, говоря о value category, имеет в виду expression evaluation, но это как-то странно.
конечно читаю и вижу что вы не понимаете как работает лайфтайм
и почему то пытаетесь где то в стандарте найти указание почему ваша скоп ссылка живет до скопа {}() а не до точки с запятой
а это не вы на здесь пару месяцев назад искали в стандарте определения массивов ?
тоже какой то чудик все пытался доказать что в С++ нет определения массивов
при этом они есть и разработчики компиляторов все реализовывают верно
вы либо упоротый разработчик компиляторов, либо тролль
и в том и другом случае лучше сразу писать в рассылку комитета по стандарту
а потом один @#$@ пропихнёт подобное в проект,
и через какое-то время люди начнут матюкаться «C++ гомно» :-)
PS. кстати во ! если очередная версия языка/библиотеки/билд-системы добавляет N фич, то в своей текущей мажорной версии можно использовать только одну. Как-бы так. На мажор - не больше одной фичи от зависимостей.
а потом один @#$@ пропихнёт подобное в проект, и через какое-то время люди начнут матюкаться «C++ гомно» :-) подобное
Что именно?
PS. кстати во ! если очередная версия языка/библиотеки/билд-системы добавляет N фич, то в своей текущей мажорной версии можно использовать только одну. Как-бы так. На мажор - не больше одной фичи от зависимостей.