Здравствуйте, rg45, Вы писали:
R>Так это и есть битая ссылка, раз объект мертвый.
Скажем так, ссылка ведёт на объект, находящийся на стеке в вызывающей функции. То есть формально она не битая. И если бы у объекта не было деструктора, то ссылка бы вообще делала вид, что всё ништяк.
R>Попробуй использовать, например, std::string вместо int — спецэффекты будут поинтереснее.
То есть ссылка возвращается нормальная. Дальше по коду строка разрушается сразу после вызова этой функции, если вывести что-то на экран, то выводится пустая строка.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Скажем так, ссылка ведёт на объект, находящийся на стеке в вызывающей функции. То есть формально она не битая. И если бы у объекта не было деструктора, то ссылка бы вообще делала вид, что всё ништяк.
Давай по порядочку.
Во-первых, деструктор формально есть у любого типа данных, даже у int. И его даже можно явно позвать: http://coliru.stacked-crooked.com/a/8360b8eef0155e2c. Просто деструктор такая хитрая штука, что он может быть определен пользователем, а может быть сгенерирован компилятором. Деструктор может быть тривиальным и нетривиальным. Но он есть всегда. И время жизни объекта, согласно стандарту, закачивается, ПРИ ВХОДЕ, в деструктор (даже если он формальный — в этом случае просто где вход, там и выход).
Во-вторых, сразу же после инициализации auto&& i = test(IntWrapper(0)); время жизни объекта IntWrapper сразу же заканчивается. От него остается только область памяти, которой компилятор может распоряжаться по своему усмотрению. Например, он может разместить в ней объект(ы) какого-нибудь типа, массивы, вообще все, что угодно. Если ты начнешь постепенно усложнять свой пример, ты в этом убедишься рано или поздно. Поэтому любое использование объекта после окончания его времени жизни ведет к UB — согласно стандарту, ессно. Несмотря на то, что ссылка указывает на валидную область памяти, ее объекта в этой области уже нет и пользоваться такой ссылкой нельзя. Вот такие ссылки, которые пережили свои объекты и которыми нельзя пользоваться, я и называю "битыми".
Здравствуйте, rg45, Вы писали:
R>Давай по порядочку.
Да, согласен, пользоваться такой ссылкой нельзя.
Другой вопрос: а чего добились кресты, уничтожая временные объекты в конце текущего выражения, а не в конце операторного блока? По расходу памяти — копейки. Зато геморроя лишнего много.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
TB>Другой вопрос: а чего добились кресты, уничтожая временные объекты в конце текущего выражения, а не в конце операторного блока? По расходу памяти — копейки. Зато геморроя лишнего много.
Ну, я могу только порассуждать на эту тему. По расходу памяти — это ведь смотря как писать код. Размеры блоков не лимитированы и число временных объектов, создаваемых в подвыражениях, могло бы зашкаливать за разумные рамки. А с другой стороны, наверное, не смогли придумать сценариев, когда бы это создавало какие-то непреодолимые трудности.
Здравствуйте, rg45, Вы писали:
R>Ну, я могу только порассуждать на эту тему. По расходу памяти — это ведь смотря как писать код. Размеры блоков не лимитированы и число временных объектов, создаваемых в подвыражениях, могло бы зашкаливать за разумные рамки.
На практике я на некотором другом языке (тоже с RAII) писал, там по сути любое выражение вида
f(g())
означало что-то типа
tmp=g();
f(tmp);
И этот tmp жил до конца текущего блока, и что-то стек с кучей от этого не переполнялись.
R>А с другой стороны, наверное, не смогли придумать сценариев, когда бы это создавало какие-то непреодолимые трудности.
Даже на чистом асме нет непреодолимых трудностей.
В данном примере трудность была создана — удалось получить ссылку на объект, у которого уже вызвался деструктор.
Да, она преодолима. Но это трудность, на решение которой будут тратиться лишние человекочасы.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
R>Во-первых, деструктор формально есть у любого типа данных, даже у int. И его даже можно явно позвать: http://coliru.stacked-crooked.com/a/8360b8eef0155e2c. Просто деструктор такая хитрая штука, что он может быть определен пользователем, а может быть сгенерирован компилятором. Деструктор может быть тривиальным и нетривиальным. Но он есть всегда. И время жизни объекта, согласно стандарту, закачивается, ПРИ ВХОДЕ, в деструктор (даже если он формальный — в этом случае просто где вход, там и выход).
Итак, смотрим в C++17 [expr.pseudo]/1: > The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the non-class type denoted by type-name or decltype-specifier. The result shall only be used as the operand for the function call operator (), and the result of such a call has type void. The only effect is the evaluation of the postfix-expression before the dot or arrow.
Никаких вызовов деструкторов (для int) и окончания его жизни...
Да, в C++20 закрыли одно CWG issue и ЕМНИП применили его решение ретроактивно, но никаких вызовов деструкторов для `int` не появилось.
[expr.call]/5: > If the postfix-expression names a pseudo-destructor (in which case the postfix-expression is a possibly-parenthesized class member access), the function call destroys the object of scalar type denoted by the object expression of the class member access ([expr.ref], [basic.life]).
[basic.life]/1: > The lifetime of an object o of type T ends when: > — if T is a non-class type, the object is destroyed, or > — if T is a class type, the destructor call starts, or > — the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).
Здравствуйте, σ, Вы писали:
σ>Итак, смотрим в C++17 [expr.pseudo]/1: >> The use of a pseudo-destructor-name after a dot . or arrow -> operator represents the destructor for the non-class type denoted by type-name or decltype-specifier. The result shall only be used as the operand for the function call operator (), and the result of such a call has type void. The only effect is the evaluation of the postfix-expression before the dot or arrow.
σ>Никаких вызовов деструкторов (для int) и окончания его жизни... σ>Да, в C++20 закрыли одно CWG issue и ЕМНИП применили его решение ретроактивно, но никаких вызовов деструкторов для `int` не появилось.
Я фигею, тетя Клава, с вашей телепередачи.
Во-первых, в данном случае рассматривается время жизни и вызов деструктора объекта типа IntWrapper, а не int.
А во-вторых, говорится же о допустимости выражений с использованием деструкторов в т.ч. для типа int. Ты же зацепился за некорректное использование слова "вызов", которое не делает погоды в данном случае от слова "совсем". Тем более, что сами же они называют это не иначе как "such a call". Да, этот самый CALL имеет ограниченный эффект, но я ничего такого и не утверждал, что этому бы противоречило.
Нельзя же так циклиться на мелочах. Ты за деревьями леса не видишь. И не в первый раз.
R>о времени жизни типа int в приведенном примере даже речи не шло, поскольку рассматривалось время жизни объекта типа IntWrapper
R> Во-первых, деструктор формально есть у любого типа данных, даже у int. И его даже можно явно позвать: http://coliru.stacked-crooked.com/a/8360b8eef0155e2c. Просто деструктор такая хитрая штука, что он может быть определен пользователем, а может быть сгенерирован компилятором. Деструктор может быть тривиальным и нетривиальным. Но он есть всегда. И время жизни объекта, согласно стандарту, закачивается, ПРИ ВХОДЕ, в деструктор (даже если он формальный — в этом случае просто где вход, там и выход).
Хочешь сказать, что это: R> деструктор формально есть у любого типа данных, даже у int. ... И время жизни объекта, согласно стандарту, закачивается, ПРИ ВХОДЕ, в деструктор (даже если он формальный — в этом случае просто где вход, там и выход).
не про то, что у int формально существует тривиальный сгенерированный компилятором деструктор при вызове которого заканчивается время жизни объекта типа int?
Здравствуйте, σ, Вы писали:
σ>[/ccode]Хочешь сказать, что это:
R> Во-первых, деструктор формально есть у любого типа данных, даже у int. И его даже можно явно позвать: http://coliru.stacked-crooked.com/a/8360b8eef0155e2c. Просто деструктор такая хитрая штука, что он может быть определен пользователем, а может быть сгенерирован компилятором. Деструктор может быть тривиальным и нетривиальным. Но он есть всегда. И время жизни объекта, согласно стандарту, закачивается, ПРИ ВХОДЕ, в деструктор (даже если он формальный — в этом случае просто где вход, там и выход).
σ>не про то, что у int формально существует тривиальный сгенерированный компилятором деструктор при вызове которого заканчивается время жизни объекта типа int?
Хочу сказать, что "формально есть" следует понимать, как "можно написать выражение". Или тебя удивляет, что я не цитирую стандарт по памяти слово в слово?
Ну а то, что после выполнения выражения i.~Int() время жизни i продолжается, для меня новость, признаюсь честно. Спасибо, конечно, но в данном случае это никак не влияет на выводы, поскольку рассматривается время жизни объекта типа IntWrapper, для которого все сказанное мной остается в силе.
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, ollv, Вы писали:
Так погоди. Давай я сначала попробую сказать точнее, почему я связываю кейсы
type& v = getrvalue();
call(getrvalue(), ...);
в обоих случаях происходит инициализация простой ссылки от рвелью. В первом случае это совсем критично, потому как в gcc (я тут даже версию не вспомню версию) есть кейсы, где это компиябильно, но продления жизни для темпорари object не происходит (и еще вопрос, происходит ли тут вообще материализация temporary object), во втором спасает только то, что оно не компилируется. т/к тоже вопрос, если вдруг произойдет кейс, где оно скомпилируется, произойдет ли там материализация temporary obj. И совершенно все равно каким рулом будет продлена жизнь темп объекта.
Видишь ли практик, я считаю, мыслит прецедентарно. Если прецедент был (а он был в практике) эта практика метится как ущербная. В этом случае совсем не тяжело просто перенести создание объекта выше.
O>> Не знаю о чем ты )) к rvalue вполне применим термин lifetime. BFE>Что обозначает lifetime для rvalue?
Да сплошь и рядом говорят lifetime of rvalue. lifetime of expression
Тут получается небольшой конфликт понятий если rvalue это выражение — то выражение суть понятия из синтаксического анализа. И мы тут перемешиваем понятия из синтаксиса и физики языка. А по сути rvalue — рантайм физика языка, а потому звать его выражением, как его понимать ? это не синтаксическое выражение ? ))
А так понятно, что касательно этого примера исключительно в С++ говорим о object lifetime.
O>>Что касается выражения, синтаксически все, что попадает в конечном счете в АСТ — expression. такова селяви синтаксического анализа. BFE>И какое отношение это имеет ко времени жизни?
а это и не о времени жизни. это о том, что "rvalue — это выражение". Хоть стандарт и показывает нам именно так, это имхо немного неровно.
O>>Объект — это уже физика языка, так вот живет объект как rvalue, выражением в данном случае будет именно std::vector<int>() -> arg, вот здесь оно и умрет, после инициализации параметра. BFE>Выражение умрёт? Или умрёт объект?
Давай так ) если считать, что мы принимаем связывание rvalue с простой ссылкой, то работает это правило
(6.9) — A temporary object bound to a reference parameter in a function call (7.6.1.2) persists until the
completion of the full-expression containing the call.
BFE>>>А вот временные объекты обязаны дожить (по стандарту) до конца выполнения выражения, O>> Только вот конец выражения будет ровно после запятой (или скобки), std::vector<int>() -> arg. BFE>Конец full-expression'а?
O>> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет. BFE>Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок?
так именно. "если проинициализируется и продлит жизнь". А то может ведь и не продлить (получим битую ссылку в теле)
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
O> Так погоди. Давай я сначала попробую сказать точнее, почему я связываю кейсы O>
O> type& v = getrvalue();
O> call(getrvalue(), ...);
O>
O> в обоих случаях происходит инициализация простой ссылки от рвелью. В первом случае это совсем критично, потому как в gcc (я тут даже версию не вспомню версию) есть кейсы, где это компиябильно, но продления жизни для темпорари object не происходит (и еще вопрос, происходит ли тут вообще материализация temporary object), во втором спасает только то, что оно не компилируется. т/к тоже вопрос, если вдруг произойдет кейс, где оно скомпилируется, произойдет ли там материализация temporary obj. И совершенно все равно каким рулом будет продлена жизнь темп объекта.
По моим представлением эти два выражения ничем не отличаются с точки зрения жизни временных объектов. Оба временных объекта должны дожить, условно говоря, "до точки с запятой". Я не совсем понимаю зачем нужно расписывать в стандарте "продление жизни" если прямо сказано, что:
Temporary objects are destroyed as the last step in evaluating the full-expression
Можно же написать: getrvalue().print();. Тут тоже есть "продление жизни"?
O>>> Не знаю о чем ты )) к rvalue вполне применим термин lifetime. BFE>>Что обозначает lifetime для rvalue? O> Да сплошь и рядом говорят lifetime of rvalue. lifetime of expression O>Тут получается небольшой конфликт понятий если rvalue это выражение — то выражение суть понятия из синтаксического анализа. И мы тут перемешиваем понятия из синтаксиса и физики языка. А по сути rvalue — рантайм физика языка, а потому звать его выражением, как его понимать ? это не синтаксическое выражение ? )) O> А так понятно, что касательно этого примера исключительно в С++ говорим о object lifetime.
Видимо из-за этой путаницы терминологии я ничего не понимаю. Есть выражения разных категорий. Они (выражения) могут либо порождать временные объекты, либо нет. Если временные объекты были материализованы, то можно говорить о времени их жизни. Зачем при этом привязывать время жизни временного объекта к категории выражения мне совершенно не понятно. Это же независимые понятия.
O>>>Объект — это уже физика языка, так вот живет объект как rvalue, выражением в данном случае будет именно std::vector<int>() -> arg, вот здесь оно и умрет, после инициализации параметра. BFE>>Выражение умрёт? Или умрёт объект? O> Давай так ) если считать, что мы принимаем связывание rvalue с простой ссылкой, то работает это правило O>
(6.9) — A temporary object bound to a reference parameter in a function call (7.6.1.2) persists until the
O>completion of the full-expression containing the call.
Зачем нужна эта сентенция, если утверждение процитированное выше —
O>>> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет. BFE>>Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок? O> так именно. "если проинициализируется и продлит жизнь". А то может ведь и не продлить (получим битую ссылку в теле)
Я не могу придумать конструкцию вызова функции без инициализации аргумента.
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, ollv, Вы писали:
O>> Так погоди. Давай я сначала попробую сказать точнее, почему я связываю кейсы O>>
O>> type& v = getrvalue();
O>> call(getrvalue(), ...);
O>>
BFE>По моим представлением эти два выражения ничем не отличаются с точки зрения жизни временных объектов. Оба временных объекта должны дожить, условно говоря, "до точки с запятой".
Таким образом простая ссылка в майкрософт, вела (сейчас они уже по умолчанию отключают такую возможность) себя как константная в стандарте.
Причем замечу
The word const was never present in this section. The rule has always been (from as long as I can remember) that a temporary used to initialize a reference has its lifetime extended to match that of the reference, regardless of the type of the reference.
И, кстати, говорят о продлении lifetime
BFE>Я не совсем понимаю зачем нужно расписывать в стандарте "продление жизни" если прямо сказано, что: BFE>
BFE>Temporary objects are destroyed as the last step in evaluating the full-expression
Меня вот это и смущает ) то, что мы то ссылаемся на стандарт, то "это проблемы стандарта" ))
BFE>Можно же написать: getrvalue().print();. Тут тоже есть "продление жизни"?
материализация временного объекта, и продление жизни до full-expression. без точки темпорари не создастся. только вот тут момент, опять таки из области синт анализа. Подозреваю, что само понятие full-expression идет именно из грамматики что-то типа
full-expression-body : expression | expression end-of-block full-expression-body
full-expression : full-expression-body end-of-scope
BFE>Видимо из-за этой путаницы терминологии я ничего не понимаю. Есть выражения разных категорий. Они (выражения) могут либо порождать временные объекты, либо нет. Если временные объекты были материализованы, то можно говорить о времени их жизни. Зачем при этом привязывать время жизни временного объекта к категории выражения мне совершенно не понятно. Это же независимые понятия.
Глядя на стандарт и диаграммку
Возникают смутные сомнения, что скопипащено оно было с некоей грамматики. Отсюда и это странное смешение — rvalue и выражения. Хотя вот эти ветвления скорее обоснованы структурами синтаксического разбора,
O>>>>Объект — это уже физика языка, так вот живет объект как rvalue, выражением в данном случае будет именно std::vector<int>() -> arg, вот здесь оно и умрет, после инициализации параметра. BFE>>>Выражение умрёт? Или умрёт объект? O>> Давай так ) если считать, что мы принимаем связывание rvalue с простой ссылкой, то работает это правило O>>
(6.9) — A temporary object bound to a reference parameter in a function call (7.6.1.2) persists until the
O>>completion of the full-expression containing the call.
BFE>Зачем нужна эта сентенция, если утверждение процитированное выше —
Так она с дополнением )) "если считать, что мы принимаем связывание rvalue с простой ссылкой, то работает это правило ...". И именно так оно и должно звучать (имхо) в практических руководствах.
на этом компиляторе видно как работает в данном случае студийный компилятор. тут простой референс ведет себя как константный. https://rextester.com/l/cpp_online_compiler_visual
O>>>> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет. BFE>>>Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок? O>> так именно. "если проинициализируется и продлит жизнь". А то может ведь и не продлить (получим битую ссылку в теле) BFE>Я не могу придумать конструкцию вызова функции без инициализации аргумента.
Но я не про инициализацию говорил, я говорил про потенциальную вероятность того, что ссылка окажется битая, т/к каким-то образом не произойдет материализация временного объекта (т/к там просто референс)
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
O>>> Так погоди. Давай я сначала попробую сказать точнее, почему я связываю кейсы O>>>
O>>> type& v = getrvalue();
O>>> call(getrvalue(), ...);
O>>>
BFE>>По моим представлением эти два выражения ничем не отличаются с точки зрения жизни временных объектов. Оба временных объекта должны дожить, условно говоря, "до точки с запятой".
O>Вот этимологически как оно было. O>https://stackoverrun.com/ru/q/6489490
O> Таким образом простая ссылка в майкрософт, вела (сейчас они уже по умолчанию отключают такую возможность) себя как константная в стандарте. O>Причем замечу O>
The word const was never present in this section. The rule has always been (from as long as I can remember) that a temporary used to initialize a reference has its lifetime extended to match that of the reference, regardless of the type of the reference.
O> И, кстати, говорят о продлении lifetime
Говорят о продлении жизни объекта для ссылки v после выполнения: type& v = getrvalue();.
Это несколько отличается от времени жизни объекта созданного в call(getrvalue(), ...);. После выполнения этого выражения объект созданный в getrvalue() умирает в отличии от объекта на который ссылается v.
type& v = getrvalue(); // (1)
call(getrvalue(), ...); // (2)
// вот тут у MS обект созданный в (1) продолжает жить, а объект созданный в (2) уже разрушен.
Поэтому, на мой взгляд, говорить о продлении жизни для объекта созданного в call(getrvalue(), ...); смысла нет.
O> Глядя на стандарт и диаграммку O>expression O> | \ O>glvalue rvalue O> | | \ O>lvalue xvalue prvalue O> Возникают смутные сомнения, что скопипащено оно было с некоей грамматики. Отсюда и это странное смешение — rvalue и выражения. Хотя вот эти ветвления скорее обоснованы структурами синтаксического разбора,
Вот тут я согласен. У меня тоже сложилось впечатление, что вместо описания языка мы имеет описание работы парсера.
O>>>>> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет. BFE>>>>Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок? O>>> так именно. "если проинициализируется и продлит жизнь". А то может ведь и не продлить (получим битую ссылку в теле) BFE>>Я не могу придумать конструкцию вызова функции без инициализации аргумента. O>Но я не про инициализацию говорил, я говорил про потенциальную вероятность того, что ссылка окажется битая, т/к каким-то образом не произойдет материализация временного объекта (т/к там просто референс)
Существование ссылки без инициализации запрещено, так что такой ситуации быть не может.
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, ollv, Вы писали:
BFE>
BFE> type& v = getrvalue(); // (1)
BFE> call(getrvalue(), ...); // (2)
BFE> // вот тут у MS обект созданный в (1) продолжает жить, а объект созданный в (2) уже разрушен.
BFE>
Я именно и пытался сказать, что ссылка обычная ссылка в МС ведет себя не по стандарту, и позволяет себя инициализировать от rvalue, что по сути и приводит к неоднозначности при переходе от одного компилятора к другому. Именно инициализация простой ссылки от rvalue и есть кривизна / опасность в данном подходе. Что собственно я и пытаюсь утверждать вот уже несколько постов. Разве что мне этимологически стало понятно откуда растут грабли. А именно потому, что майкрософт решила взять поведение ссылки, которое было еще до появления стандарта.
BFE>Поэтому, на мой взгляд, говорить о продлении жизни для объекта созданного в call(getrvalue(), ...); смысла нет.
Я думаю, что вопрос тут скорее о тех кейсах, в которых gcc таки соберет код, в котором идет инициализация ссылки от rvalue, но вот extend lifetime не произойдет (или материализации темп объекта). Имхо такие вещи лучше снабжать комментариями, и пытаться избегать инициализации простой ссылки rvalue. Т/е падение точно было type& r = getrvalue(); т/к здесь шло получение битой ссфлки.
O>> Глядя на стандарт и диаграммку O>>expression O>> | \ O>>glvalue rvalue O>> | | \ O>>lvalue xvalue prvalue O>> Возникают смутные сомнения, что скопипащено оно было с некоей грамматики. Отсюда и это странное смешение — rvalue и выражения. Хотя вот эти ветвления скорее обоснованы структурами синтаксического разбора,
BFE>Вот тут я согласен. У меня тоже сложилось впечатление, что вместо описания языка мы имеет описание работы парсера.
O>>>>>> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет. BFE>>>>>Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок? O>>>> так именно. "если проинициализируется и продлит жизнь". А то может ведь и не продлить (получим битую ссылку в теле) BFE>>>Я не могу придумать конструкцию вызова функции без инициализации аргумента. O>>Но я не про инициализацию говорил, я говорил про потенциальную вероятность того, что ссылка окажется битая, т/к каким-то образом не произойдет материализация временного объекта (т/к там просто референс) BFE>Существование ссылки без инициализации запрещено, так что такой ситуации быть не может.
Вопрос чем? Речь идет о не безопасности такого подхода вообще.
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, rg45, Вы писали:
R>>Ну, я могу только порассуждать на эту тему. По расходу памяти — это ведь смотря как писать код. Размеры блоков не лимитированы и число временных объектов, создаваемых в подвыражениях, могло бы зашкаливать за разумные рамки.
TB>На практике я на некотором другом языке (тоже с RAII) писал, там по сути любое выражение вида TB>
TB>f(g())
TB>
TB>означало что-то типа TB>
TB>tmp=g();
TB>f(tmp);
TB>
TB>И этот tmp жил до конца текущего блока, и что-то стек с кучей от этого не переполнялись.
Ну о куче тут вообще нет разговора, а вот стек ) это до поры до времени. Вот внедрится эта хрень куда-то в рекурсивный разбор,
foo(v = g())
{
foo(g());
// и тут вычисления, что исключит оптимизацию в хвостовую рекурсию и вуаля, стек будет выеден мгновенно
}
R>>А с другой стороны, наверное, не смогли придумать сценариев, когда бы это создавало какие-то непреодолимые трудности.
TB>Даже на чистом асме нет непреодолимых трудностей.
есть, в реальных проектах вполне.
TB>В данном примере трудность была создана — удалось получить ссылку на объект, у которого уже вызвался деструктор. TB>Да, она преодолима. Но это трудность, на решение которой будут тратиться лишние человекочасы.
Лишние человекочасы это не снос проекта, когда логика изменений для простой задачи размазывается по всему 10*n-летнему коду. или при появлении новых технологий проект безнадежно устаревает, и сделать с ним ничего нельзя.
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
O>foo(v = g()) O>{ O> foo(g()); O> // и тут вычисления, что исключит оптимизацию в хвостовую рекурсию и вуаля, стек будет выеден мгновенно O>}
Такой случай элементарно обходится, и то мне такое не попадалось. А вот смерть объекта раньше ожидаемого — попадалась.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, ollv, Вы писали:
O>>foo(v = g()) O>>{ O>> foo(g()); O>> // и тут вычисления, что исключит оптимизацию в хвостовую рекурсию и вуаля, стек будет выеден мгновенно O>>}
TB>Такой случай элементарно обходится, и то мне такое не попадалось.
А вот я не сказал бы. Особенно, если на рекурсивном движке построены нетривиальные вычисления, это далеко не элементарная (кстати как там элементарная — не значит несложная) задача.
TB>А вот смерть объекта раньше ожидаемого — попадалась.
Да, и мне попадалось и попадается такое в очень разных языках, когда ресурс оказывается мертвым, или же наоборот ресурс висит. лайфтайм аднака ресурсы и технологии. И, знаешь, наверное это каким-то образом можно посчитать. Завести статистику, градации сложности. Старость / используемость / цитируемость ... куча параметров языков, и сравнивать. Главное о параметрах договориться, и можно сравнивать и прочее )) а так просто о чем говорить? Что на нете, хацкеле, и прочих нет bottle neck ? Просто, как бы мы обсуждаем язык со своей уже success story. А победителей не расстреливают ))
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
O> А вот я не сказал бы. Особенно, если на рекурсивном движке построены нетривиальные вычисления, это далеко не элементарная (кстати как там элементарная — не значит несложная) задача.
{} вокруг foo
O> Да, и мне попадалось и попадается такое в очень разных языках, когда ресурс оказывается мертвым, или же наоборот ресурс висит. лайфтайм аднака ресурсы и технологии.
Я про стековые объекты
O> Просто, как бы мы обсуждаем язык со своей уже success story. А победителей не расстреливают ))
Кобол, Паладин, С++...
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Шахтер, Вы писали:
Ш>>Нет. Возвращаемое значение должно быть rvalue.
Ш>>Коряво.
W>Коряво? Криво? Легко использовать неверно в другом контексте? W>Вот с этим можно согласится. W>А то, что "возвращаемое значение должно быть rvalue" — это выдумка. Нет такого требования, конечно же
ТС хотел сделать
inline
std::vector<int> makeVec( int i )
{
std::vector<int> ret;
ret.push_back(i);
return ret;
}
Только записать в одну строку. Здесь хочется move в return. Для этого нужно rvalue.
inline
std::vector<int> makeVec( int i )
{
returnpush_back_helper( std::vector<int>(), i );
}