LINUX.ORG.RU

Продление жизни rvalue

 


3

4

Привет.

#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.

★★

Последнее исправление: pavlick (всего исправлений: 1)

т.е. объекту стоило бы уничтожиться после двоеточия.

Всмысле после ; строчке

S &&r = (S &&) S{};
?

запустив тест получается, что объект переживает cout,

Ссылка «продлевает» жизнь обьекта в рамках scope.

https://en.cppreference.com/w/cpp/language/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.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от KennyMinigun

Ну это я читал, продливать жизнь можно лишь один раз - при первой привязки 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 &&)

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 2)
Ответ на: комментарий от pavlick

Ну это я читал, продливать жизнь можно лишь один раз - при первой привязки prvalue к ссылке.

У тебя в коде так и джелается. 100% легально.

In general, the lifetime of a temporary cannot be further extended by «passing it on»:

А тут идется про что-то такое:

const S& make() {
  const S& ref = S{};
  return ref;
}
https://wandbox.org/permlink/6u3Wfz3crdcoRmeh

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от pavlick

С другой стороны, что-то мне подсказывает, что

S&& make() {
  S&& ref = S{};
  return std::move(ref);
}

Вполне валидный код, т.к. ownership transfer. Но не могу найти подтверждения своему предположению, подпишусь на тред.

KennyMinigun ★★★★★
()
Ответ на: комментарий от pavlick

И в неявной форме такое поведение используют повсеместно. Например можно мувать объекты из вектора. Не говоря уже о perfect forwarding-е где используется ровно эта же цепочка кастов.

Kuzy ★★★
()
Ответ на: комментарий от KennyMinigun

ну там явное копирование ссылок, никакого продления быть не может. Даже если в возвращаемый тип функции ссылка и мы кидаем в 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.
...

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)

http://eel.is/c draft/class.temporary#6.8

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).

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

да похоже на то, благодарю за ссылку.

pavlick ★★
() автор топика

Где тут две инициализации ссылки? Каст — это не инициализация ссылки.

Продление жизни rvalue

У rvalue нет никакой жизни. rvalue — это такой подкласс выражений (привет, tailgunner). Время жизни бывает у объектов (и ссылок).

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Ответ на: комментарий от xaizek

Шестой пункт расписали подробно после C++17. Т.е. только в C++20 в стандарте появятся ясные правила, при какой форме инициализирующего выражения байндинг к ссылке продлевает lifetime временного объекта, создаваемого в этом выражении. См. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0727r0.html

utf8nowhere ★★★
()
Ответ на: комментарий от pavlick

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

Что такое «копирование ссылок»?

utf8nowhere ★★★
()
Ответ на: комментарий от intelfx

Да, и std::move в конце убивает диагностику. Похоже на баг.

KennyMinigun ★★★★★
()
Ответ на: комментарий от pavlick

т.е. prvalue должен умереть после смерти (S &&)

Что такое «смерть (S &&)»?

utf8nowhere ★★★
()

А мне вот что интересно :-) Такие вопросы возникают из реальных задач вне локалхоста, или это просто поиск приключений? :-) Зачем лезть в эти закоулки цепепе? :-) Это для того, чтобы написать тарабарщину, которую потом кто-то другой будет вынужден читать с засаленным справочником, отыскивая в нём лайфтаймы этих крючков? :-) Почувствовать себя гением? :-) Лол :-)

anonymous
()
Ответ на: комментарий от anonymous

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

KennyMinigun ★★★★★
()
Ответ на: комментарий от KennyMinigun

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

И, наверное, эти вопросы возникают на кухне после рефакторинга кода очередного куллхацкера, который активно поработал с лайфтаймами rvalue? :-)

anonymous
()
Ответ на: комментарий от anonymous

а кухне после рефакторинга кода очередного куллхацкера

Почему же? Самые острые обсуждения выходят после поиска «той самой» неуловимой баги. В частности из-за UB, на которое не обратил внимание или не знал.

KennyMinigun ★★★★★
()
Ответ на: комментарий от utf8nowhere

Где тут две инициализации ссылки? Каст — это не инициализация ссылки.

А как можно выполнить такое вот выражение не создав две ссылки (без учёта всяких там оптимизаций компилятора)?

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», ну и к чему эта педантичность?

Что такое «копирование ссылок»?

Инициализация ссылки другой ссылкой.

pavlick ★★
() автор топика
Ответ на: комментарий от anonymous

Довольно кривой ответ. Хотя, может в 2015-м году он и соответствовал кривому wording-у в стандарте.

Первый ответ хотя бы указывает на правильный issue, только вот термин «temporary expression» не определили и точно не определят, а оставшиеся 2.5 места в стандарте, где употребляется это бессмысленное словосочетание, скоро наконец вычистят.

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Ответ на: комментарий от utf8nowhere

в чем кривой ? пример не рабочий или плохо объясняет что такое лайфтайм ?
или вам только слово темпорари не понравилось ?

anonymous
()
Ответ на: комментарий от anonymous

или вам только слово темпорари не понравилось ?

В основном это, да.

utf8nowhere ★★★
()
Ответ на: комментарий от anonymous

вы в гугл ходите прежде чем вопросы задавать ?

А вы тему читаете прежде чем ответы выдавать? Я и без стековерфлоу знал, что инициализация ссылки в return не продливает жизнь ни при каких условиях. Более того, писал выше об этом.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

А как можно выполнить такое вот выражение не создав две ссылки (без учёта всяких там оптимизаций компилятора)?

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

Исправят — скину.

Когда говорят о value категориях выражений, то имеют в виду их «expression evaluation» - т.е. то, что останется после расчёта выражения.

Я смотрю в http://eel.is/c draft/intro.execution#def:evaluation и мне кажется, что не это имеют в виду.

предлагаете выражаться в подобном стиле: «Продление жизни expression evaluation of prvalue expression»

(Начиная с C++17) evaluation of prvalue expression даже не создаёт (временных) объектов. Продлевать жизнь нечему.

Предлагаю выражаться в стиле: «продление жизни временных объектов». Не сильно длиннее, чем «продление жизни rvalue» и корректно.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Я смотрю в 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;
...

https://en.cppreference.com/w/cpp/language/value_category

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

Не знаю как иначе это можно понять:

Я не могу понять, что ты хочешь сказать, но попробую ответить: когда говорят о value category имеют в виду value category, а когда говорят об expression evaluation имеют в виду expression evaluation.

Возможно кто-то, говоря о value category, имеет в виду expression evaluation, но это как-то странно.

utf8nowhere ★★★
()
Ответ на: комментарий от pavlick

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

anonymous
()
Ответ на: комментарий от zaz

В С++ время жизни объекта задается операторами {} либо ()

Угу, только В C++ нет оператора {}.

anonymous
()
Ответ на: комментарий от anonymous

в интернете не принято создавать избыточность

anonymous
()

а потом один @#$@ пропихнёт подобное в проект, и через какое-то время люди начнут матюкаться «C++ гомно» :-)

PS. кстати во ! если очередная версия языка/библиотеки/билд-системы добавляет N фич, то в своей текущей мажорной версии можно использовать только одну. Как-бы так. На мажор - не больше одной фичи от зависимостей.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

а потом один @#$@ пропихнёт подобное в проект, и через какое-то время люди начнут матюкаться «C++ гомно» :-)
подобное

Что именно?

PS. кстати во ! если очередная версия языка/библиотеки/билд-системы добавляет N фич, то в своей текущей мажорной версии можно использовать только одну. Как-бы так. На мажор - не больше одной фичи от зависимостей.

Ты слишком много работаешь с JS.

KennyMinigun ★★★★★
()
#include <iostream>
using namespace std;
struct S{
  ~S() {cout << "destr\n";}
};
int main(){
  S &&r = (S &&) S{};
  // const S &r = (S &&) S{}; // аналогично
  cout << "-------------\n";
}

gcc 7.2.0 -std=c++17 никаких destr не выводится, ссылка живет до точки с запятой

anonymous
()
Ответ на: комментарий от anonymous

а не, пардон, не то скомпилил

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.