Ш>Нет. Возвращаемое значение должно быть rvalue.
Ш>Коряво.
Коряво? Криво? Легко использовать неверно в другом контексте?
Вот с этим можно согласится.
А то, что "возвращаемое значение должно быть rvalue" — это выдумка. Нет такого требования, конечно же
Почему нет? Ну функция должна вернуть вектор по значению. Ей приходит какая-то ссылка. Ну, по идее она смувает вектор из ссылки в возвращаемый адрес, но может сразу вектор по этой ссылке создавать. Короче, не вижу тут UB
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Marty, Вы писали:
M>Здравствуйте!
M>
M>template<typename ItemType>
M>inline
M>std::vector<ItemType>& push_back_helper( std::vector<ItemType> &v, const ItemType &elem )
M>{
M> v.push_back(elem);
M> return v;
M>}
M>inline
M>std::vector<int> makeVec( int i )
M>{
M> return push_back_helper( std::vector<int>(), i );
M>}
M>int main()
M>{
M> auto v = makeVec( 3 );
M>}
M>
под майкрософт может работать без проблем. Под gcc будет сигфолт, после передачи инстанса вектора он умрет при свертке стека (а именно после возврата из push_back_helper(std::vector<int>(), ... ) )У майкрософта была какая-то "оптимизация" по продлению жизни ссылки
M>Вроде ничему не противоречит, но решил уточнить
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
M>>template<typename ItemType>
M>>inline
M>>std::vector<ItemType>& push_back_helper( std::vector<ItemType> &v, const ItemType &elem )
M>>{
M>> v.push_back(elem);
M>> return v;
M>>}
M>>inline
M>>std::vector<int> makeVec( int i )
M>>{
M>> return push_back_helper( std::vector<int>(), i );
M>>}
M>>int main()
M>>{
M>> auto v = makeVec( 3 );
M>>}
M>>
O> Под gcc будет сигфолт, после передачи инстанса вектора он умрет при свертке стека (а именно после возврата из push_back_helper(std::vector<int>(), ... ) )У майкрософта была какая-то "оптимизация" по продлению жизни ссылки
Сигфолта не будет, т.к. не скомпилируется.
Но даже если добавить функцию:
Даже тогда Сигфолта не будет, т.к. std::vector<int>() должен дожить до конца выполнения выражения push_back_helper( std::vector<int>(), i );, которое включает в себя копирование вектора в возвращаемый результат
inline
std::vector<int> makeVec( int i )
{
return push_back_helper( std::vector<int>(), i );
}
Здравствуйте, B0FEE664, Вы писали: BFE>Здравствуйте, ollv, Вы писали:
Скрытый текст
M>>>
M>>>template<typename ItemType>
M>>>inline
M>>>std::vector<ItemType>& push_back_helper( std::vector<ItemType> &v, const ItemType &elem )
M>>>{
M>>> v.push_back(elem);
M>>> return v;
M>>>}
M>>>inline
M>>>std::vector<int> makeVec( int i )
M>>>{
M>>> return push_back_helper( std::vector<int>(), i );
M>>>}
M>>>int main()
M>>>{
M>>> auto v = makeVec( 3 );
M>>>}
M>>>
BFE> O>> Под gcc будет сигфолт, после передачи инстанса вектора он умрет при свертке стека (а именно после возврата из push_back_helper(std::vector<int>(), ... ) )У майкрософта была какая-то "оптимизация" по продлению жизни ссылки
BFE>Сигфолта не будет, т.к. не скомпилируется.
Да на gcc compile rvalue не ляжет в ссылку. просто майкрософт ведет себя вероломно. Т/к/ он мало того, что компилирует, так еще и без ворнингов (с настройками по умолчанию). Его конечно можно нагнуть, чтобы такое не компилировалось но это опасности не отменяет.
+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов
В общем, я могу сказать одно, я такие практики оч не поддерживаю.
такое скомпилируется и может даже имеет какой-то смысл. Но изначально — r& fun(type& v) { return v; }
я пытаюсь избегать, именно по причине того, что майкрософт ведет себя вероломно.
inline
std::vector<int> makeVec( int i )
{
std::vector<int> r;
return push_back_helper(r, i );
}
BFE>Даже тогда Сигфолта не будет, т.к. std::vector<int>() должен дожить до конца выполнения выражения push_back_helper( std::vector<int>(), i );, которое включает в себя копирование вектора в возвращаемый результат
BFE>
BFE>inline
BFE>std::vector<int> makeVec( int i )
BFE>{
BFE> return push_back_helper( std::vector<int>(), i );
BFE>}
BFE>
зачем тут мув семантика вообще непонятно. я вообще не понимаю зачем весь этот сырбор, если РВО помогает мейкать вектора и прочие объекты без потерь
все уже сделано в решениях вида std::make_shared_ptr и прочих bind. Параметры муваются, объекты создаются и возвращаются без потерь.
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
BFE>>Сигфолта не будет, т.к. не скомпилируется. O>Да на gcc compile rvalue не ляжет в ссылку. просто майкрософт ведет себя вероломно. Т/к/ он мало того, что компилирует, так еще и без ворнингов (с настройками по умолчанию). Его конечно можно нагнуть, чтобы такое не компилировалось но это опасности не отменяет.
В чём опасность? Такой код компилируется и работает у Майкрософта более 15-ти лет, ещё до принятия стандарта 2011-ого года, до move семантики. То, что это не по стандарту — это проблемы стандарта, а не кода.
O>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов
Здесь нет продления жизни для ссылок.
O>В общем, я могу сказать одно, я такие практики оч не поддерживаю.
Никакой особой практики я тут не вижу. Это довольно редкий случай, как правило порождаемый при переиспользовании кода в ситуациях не предвиденных изначально.
O>такое скомпилируется и может даже имеет какой-то смысл. Но изначально — r& fun(type& v) { return v; } O>я пытаюсь избегать, именно по причине того, что майкрософт ведет себя вероломно.
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, ollv, Вы писали:
BFE>>>Сигфолта не будет, т.к. не скомпилируется. O>>Да на gcc compile rvalue не ляжет в ссылку. просто майкрософт ведет себя вероломно. Т/к/ он мало того, что компилирует, так еще и без ворнингов (с настройками по умолчанию). Его конечно можно нагнуть, чтобы такое не компилировалось но это опасности не отменяет.
BFE>В чём опасность? Такой код компилируется и работает у Майкрософта более 15-ти лет, ещё до принятия стандарта 2011-ого года, до move семантики. То, что это не по стандарту — это проблемы стандарта, а не кода.
Ну давай в политику такие вопросы )) Я считаю, что если ты пишешь на С++ такое typename calc_type<somw_arg>::type v = get_foo(); должно работать одинаково. На то он и стандарт. Кстати, сейчас майкрософт работает над этим. И по моему уже так просто в ссылку rvalue не пихнуть
O>>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов BFE>Здесь нет продления жизни для ссылок.
есть но завуалированное. ссылка принимает rvalue и объект живет, в то время как rvalue уже умирает по стандарту после вызова конструктора. Потому оно и не компилируется в джисях
O>>В общем, я могу сказать одно, я такие практики оч не поддерживаю. BFE>Никакой особой практики я тут не вижу. Это довольно редкий случай, как правило порождаемый при переиспользовании кода в ситуациях не предвиденных изначально.
нет не редкий. встречается постоянно. тебя спасет только если ты пишешь только под мягких, с мультиплатформенностью таких практик (я лично) избегаю. просто потому как при вычислении типа легко можно получить такой эффект ..
и это ) ты считай как считаешь нужным. я не вижу даже смысла тут дискуссию заводить
O>>такое скомпилируется и может даже имеет какой-то смысл. Но изначально — r& fun(type& v) { return v; } O>>я пытаюсь избегать, именно по причине того, что майкрософт ведет себя вероломно.
BFE>Веру в что ломает майкрософт?
Ты собрался в этимологию слова вероломно уходить? смысл в том, что один и тот-же код может работать по разному в зависимости от платформы в ключевом (как я считаю) контексте. А должен работать одинаково
ну это мое мнение. Ты можешь считать, что это проблема стандарта, а не майкрософт С++, но я считаю иначе. Чисто математически это — верно. Но политически ты можешь с этим поспорить. У меня желания нет ))
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Здравствуйте, ollv, Вы писали:
BFE>>В чём опасность? Такой код компилируется и работает у Майкрософта более 15-ти лет, ещё до принятия стандарта 2011-ого года, до move семантики. То, что это не по стандарту — это проблемы стандарта, а не кода. O> Ну давай в политику такие вопросы )) Я считаю, что если ты пишешь на С++ такое typename calc_type<somw_arg>::type v = get_foo(); должно работать одинаково. На то он и стандарт. Кстати, сейчас майкрософт работает над этим. И по моему уже так просто в ссылку rvalue не пихнуть
Это не политика. Это та проблема стандарта, которую решили введением move семантики. Только вот Майкрософт эту проблему пытался решить до введения move семантики и из-за обратной совместимости отказаться от такого решения не может.
O>>>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов BFE>>Здесь нет продления жизни для ссылок. O>есть но завуалированное. ссылка принимает rvalue и объект живет, в то время как rvalue уже умирает по стандарту после вызова конструктора. Потому оно и не компилируется в джисях
rvalue — это выражение, оно не может жить или умереть.
А вот временные объекты обязаны дожить (по стандарту) до конца выполнения выражения, так что вектор std::vector<int>() обязан дожить до конца выполнения функции push_back_helper.
Здравствуйте, T4r4sB, Вы писали:
TB>Почему нет? Ну функция должна вернуть вектор по значению. Ей приходит какая-то ссылка. Ну, по идее она смувает вектор из ссылки в возвращаемый адрес, но может сразу вектор по этой ссылке создавать. Короче, не вижу тут UB
Возможен сценарий получения битой ссылки. При нынешних-то тенденциях максимально широкого использования auto&&:
auto&& v = push_back_helper( std::vector<int>(), i );
В то время как при возврате по значению это полностью безопасный код.
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, ollv, Вы писали:
BFE>Это не политика. Это та проблема стандарта, которую решили введением move семантики. Только вот Майкрософт эту проблему пытался решить до введения move семантики и из-за обратной совместимости отказаться от такого решения не может.
это и есть политика. Неконстантная ссылка не должна продлевать жизнь объекта, по стандарту. У майкрософта это не так. Считать допустимо это, или нет — вопрос политический.
O>>>>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов BFE>>>Здесь нет продления жизни для ссылок. O>>есть но завуалированное. ссылка принимает rvalue и объект живет, в то время как rvalue уже умирает по стандарту после вызова конструктора. Потому оно и не компилируется в джисях BFE>rvalue — это выражение, оно не может жить или умереть.
Не знаю о чем ты )) к rvalue вполне применим термин lifetime. Что касается выражения, синтаксически все, что попадает в конечном счете в АСТ — expression. такова селяви синтаксического анализа. Объект — это уже физика языка, так вот живет объект как rvalue, выражением в данном случае будет именно std::vector<int>() -> arg, вот здесь оно и умрет, после инициализации параметра.
BFE>А вот временные объекты обязаны дожить (по стандарту) до конца выполнения выражения,
Только вот конец выражения будет ровно после запятой (или скобки), std::vector<int>() -> arg. И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет.
BFE>так что вектор std::vector<int>() обязан дожить до конца выполнения функции push_back_helper.
Не совсем понимаю, что тут кто кому должен, если такая передача некорректна изначально. майкрософтовский вариант скорее попытка решить свои проблемы, за счет стандарта. И это — политика.
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Ш>Но, вообще, это плохо. Коряво. Ш>Лучше сделать что-то вроде
Я бы предложил еще один подход, основанный на максимально полном использовании perfect forwarding references. УПРОЩЕННЫЙ вариант, демонстрирующий идею, выглядит так:
Для тех, кто пока еще не понял, в чем фокус (а такие есть, я уверен): это функция-универсал — может возвращать как ссылку, так и значение — в зависимости от типа входного параметра. Когда входной параметр задается lvalue выражением, хоть константным, хоть неконстантным, функция возвращает lvalue ссылку — константную или неконстантную. Если же параметр задается rvalue выражением, функция вернет значение, применив при этом move. Преимущество такого подхода — одним выстрелом получается неплохой компромисс между эффективностью и надежностью. Код защищен от опасности возникновения висячих ссылок.
Ну а перегрузки и типовую безопасность придется достигать использованием SFINAE или концептов. И это слабая сторона такого подхода.
Здравствуйте, ollv, Вы писали:
O>>>>>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов BFE>>>>Здесь нет продления жизни для ссылок. O>>>есть но завуалированное. ссылка принимает rvalue и объект живет, в то время как rvalue уже умирает по стандарту после вызова конструктора. Потому оно и не компилируется в джисях BFE>>rvalue — это выражение, оно не может жить или умереть. O> Не знаю о чем ты )) к rvalue вполне применим термин lifetime.
Что обозначает lifetime для rvalue?
O>Что касается выражения, синтаксически все, что попадает в конечном счете в АСТ — expression. такова селяви синтаксического анализа.
И какое отношение это имеет ко времени жизни?
O>Объект — это уже физика языка, так вот живет объект как rvalue, выражением в данном случае будет именно std::vector<int>() -> arg, вот здесь оно и умрет, после инициализации параметра.
Выражение умрёт? Или умрёт объект?
BFE>>А вот временные объекты обязаны дожить (по стандарту) до конца выполнения выражения, O> Только вот конец выражения будет ровно после запятой (или скобки), std::vector<int>() -> arg.
Конец full-expression'а?
O> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет.
Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок?
Здравствуйте, T4r4sB, Вы писали:
TB>Превращается в возврат 1 TB>((( TB>По коду ссылка не битая, но она указывает на мёртвый объект, у которого уже вызван деструктор
Так это и есть битая ссылка, раз объект мертвый. Вот эта единица — это просто стековый мусор, значение которого по случайности совпало с оригиналом. Попробуй использовать, например, std::string вместо int — спецэффекты будут поинтереснее.