Правомерно ли такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.08.20 16:43
Оценка:
Здравствуйте!

template<typename ItemType>
inline
std::vector<ItemType>& push_back_helper( std::vector<ItemType> &v, const ItemType &elem )
{
    v.push_back(elem);
    return v;
}

inline
std::vector<int> makeVec( int i )
{
    return push_back_helper( std::vector<int>(), i );
}

int main()
{
    auto v = makeVec( 3 );
}



Вроде ничему не противоречит, но решил уточнить
Маньяк Робокряк колесит по городу
Re: Правомерно ли такое
От: σ  
Дата: 16.08.20 16:56
Оценка: +1
Оно даже не скомпилируется. Должно быть:
push_back_helper(std::vector<ItemType>&& v, const ItemType& elem)
                                      ^^
Ну а так — правомерно.
Re[2]: Правомерно ли такое
От: Шахтер Интернет  
Дата: 16.08.20 18:01
Оценка:
Здравствуйте, σ, Вы писали:

σ>Оно даже не скомпилируется. Должно быть:

σ>
σ>push_back_helper(std::vector<ItemType>&& v, const ItemType& elem)
σ>                                      ^^
σ>
Ну а так — правомерно.


Нет. Возвращаемое значение должно быть rvalue. Т.е. надо как-то так

template<typename ItemType>
inline
std::vector<ItemType>&& push_back_helper( std::vector<ItemType> &&v, const ItemType &elem )
{
    v.push_back(elem);
    return std::move(v);
}


Но, вообще, это плохо. Коряво.

Лучше сделать что-то вроде

template <class T>
struct VectorInit : public std::vector<T>
 {
  template <class Func>
  VectorInit(Func func) { func((std::vector<T> &)*this); } 
 };
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Правомерно ли такое
От: watchmaker  
Дата: 16.08.20 18:13
Оценка:
Здравствуйте, Шахтер, Вы писали:


Ш>Нет. Возвращаемое значение должно быть rvalue.


Ш>Коряво.


Коряво? Криво? Легко использовать неверно в другом контексте?
Вот с этим можно согласится.
А то, что "возвращаемое значение должно быть rvalue" — это выдумка. Нет такого требования, конечно же
Re[3]: Правомерно ли такое
От: σ  
Дата: 16.08.20 18:50
Оценка: :))
Ш>Но, вообще, это плохо. Коряво.

Это-то ясно. Под "правомерно" я подразумевал только лишь отсутствие UB.

Ш>Лучше сделать что-то вроде

Ш>
template <class T>
struct VectorInit : public std::vector<T>
 {
  template <class Func>
  VectorInit(Func func) { func((std::vector<T> &)*this); } 
 };

А это какое-то ООП головного мозга в терминальной стадии.
Но да, выглядит ънтерпрайзно. Почти так же солидно, как AbstractSingletonProxyFactoryBean
Отредактировано 16.08.2020 18:52 σ . Предыдущая версия .
Re[2]: Правомерно ли такое
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.08.20 20:02
Оценка:
Здравствуйте, σ, Вы писали:

σ>Оно даже не скомпилируется. Должно быть:

σ>
σ>push_back_helper(std::vector<ItemType>&& v, const ItemType& elem)
σ>                                      ^^
σ>
Ну а так — правомерно.


0x03, компилируется, и даже работает
Маньяк Робокряк колесит по городу
Re[3]: Правомерно ли такое
От: T4r4sB Россия  
Дата: 16.08.20 21:03
Оценка:
Здравствуйте, Шахтер, Вы писали:


Ш>Но, вообще, это плохо. Коряво.


Почему нет? Ну функция должна вернуть вектор по значению. Ей приходит какая-то ссылка. Ну, по идее она смувает вектор из ссылки в возвращаемый адрес, но может сразу вектор по этой ссылке создавать. Короче, не вижу тут UB
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Правомерно ли такое
От: AeroSun  
Дата: 16.08.20 21:40
Оценка:
А зачем? Не понял чего этим хочется добиться?
Re: Правомерно ли такое
От: ollv СССР https://youtu.be/DQDoYs6wHoo
Дата: 17.08.20 12:10
Оценка:
Здравствуйте, 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. Я болен ПГМ.
Отредактировано 17.08.2020 12:24 Маркуша Шулин . Предыдущая версия .
Re[2]: Правомерно ли такое
От: B0FEE664  
Дата: 17.08.20 12:47
Оценка:
Здравствуйте, 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>>

O> Под gcc будет сигфолт, после передачи инстанса вектора он умрет при свертке стека (а именно после возврата из push_back_helper(std::vector<int>(), ... ) )У майкрософта была какая-то "оптимизация" по продлению жизни ссылки
Сигфолта не будет, т.к. не скомпилируется.
Но даже если добавить функцию:
template<typename ItemType>
inline std::vector<ItemType>& push_back_helper( std::vector<ItemType>&& v, const ItemType &elem )
{
    v.push_back(elem);
    return v;
}

Даже тогда Сигфолта не будет, т.к. 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 );
}
И каждый день — без права на ошибку...
Re[3]: Правомерно ли такое
От: ollv СССР https://youtu.be/DQDoYs6wHoo
Дата: 18.08.20 07:31
Оценка:
Здравствуйте, 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>Но даже если добавить функцию:

BFE>
BFE>template<typename ItemType>
BFE>inline std::vector<ItemType>& push_back_helper( std::vector<ItemType>&& v, const ItemType &elem )
BFE>{
BFE>    v.push_back(elem);
BFE>    return v;
BFE>}
BFE>

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. Я болен ПГМ.
Отредактировано 18.08.2020 7:43 Маркуша Шулин . Предыдущая версия . Еще …
Отредактировано 18.08.2020 7:41 Маркуша Шулин . Предыдущая версия .
Отредактировано 18.08.2020 7:40 Маркуша Шулин . Предыдущая версия .
Отредактировано 18.08.2020 7:38 Маркуша Шулин . Предыдущая версия .
Re[4]: Правомерно ли такое
От: B0FEE664  
Дата: 18.08.20 08:35
Оценка:
Здравствуйте, ollv, Вы писали:

BFE>>Сигфолта не будет, т.к. не скомпилируется.

O>Да на gcc compile rvalue не ляжет в ссылку. просто майкрософт ведет себя вероломно. Т/к/ он мало того, что компилирует, так еще и без ворнингов (с настройками по умолчанию). Его конечно можно нагнуть, чтобы такое не компилировалось но это опасности не отменяет.

В чём опасность? Такой код компилируется и работает у Майкрософта более 15-ти лет, ещё до принятия стандарта 2011-ого года, до move семантики. То, что это не по стандарту — это проблемы стандарта, а не кода.

O>+ к тому есть продление жизни для ссылок — тоже опасное поведение, с такими трюками можно легко запутаться особенно присутствуют сложные вычисления типов

Здесь нет продления жизни для ссылок.

O>В общем, я могу сказать одно, я такие практики оч не поддерживаю.

Никакой особой практики я тут не вижу. Это довольно редкий случай, как правило порождаемый при переиспользовании кода в ситуациях не предвиденных изначально.

O>такое скомпилируется и может даже имеет какой-то смысл. Но изначально — r& fun(type& v) { return v; }

O>я пытаюсь избегать, именно по причине того, что майкрософт ведет себя вероломно.

Веру в что ломает майкрософт?
И каждый день — без права на ошибку...
Re[5]: Правомерно ли такое
От: ollv СССР https://youtu.be/DQDoYs6wHoo
Дата: 18.08.20 09:06
Оценка:
Здравствуйте, 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. Я болен ПГМ.
Re[6]: Правомерно ли такое
От: B0FEE664  
Дата: 18.08.20 09:43
Оценка:
Здравствуйте, 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.
И каждый день — без права на ошибку...
Re[4]: Правомерно ли такое
От: rg45 СССР  
Дата: 18.08.20 10:26
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Почему нет? Ну функция должна вернуть вектор по значению. Ей приходит какая-то ссылка. Ну, по идее она смувает вектор из ссылки в возвращаемый адрес, но может сразу вектор по этой ссылке создавать. Короче, не вижу тут UB


Возможен сценарий получения битой ссылки. При нынешних-то тенденциях максимально широкого использования auto&&:

auto&& v = push_back_helper( std::vector<int>(), i );


В то время как при возврате по значению это полностью безопасный код.
--
Re[7]: Правомерно ли такое
От: ollv СССР https://youtu.be/DQDoYs6wHoo
Дата: 18.08.20 10:34
Оценка:
Здравствуйте, 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. Я болен ПГМ.
Re[3]: Правомерно ли такое
От: rg45 СССР  
Дата: 18.08.20 11:20
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>
Ш>template<typename ItemType>
Ш>inline
Ш>std::vector<ItemType>&& push_back_helper( std::vector<ItemType> &&v, const ItemType &elem )
Ш>{
Ш>    v.push_back(elem);
Ш>    return std::move(v);
Ш>}
Ш>


Ш>Но, вообще, это плохо. Коряво.

Ш>Лучше сделать что-то вроде

Я бы предложил еще один подход, основанный на максимально полном использовании perfect forwarding references. УПРОЩЕННЫЙ вариант, демонстрирующий идею, выглядит так:

template<typename ContainerT typename ItemT>
ContainerT push_back_helper(ContainerT&& v, ItemT&& item)
{
    v.push_back(std::forward<ItemT>(item));
    return std::forward<ContainerT>(v);
}


Для тех, кто пока еще не понял, в чем фокус (а такие есть, я уверен): это функция-универсал — может возвращать как ссылку, так и значение — в зависимости от типа входного параметра. Когда входной параметр задается lvalue выражением, хоть константным, хоть неконстантным, функция возвращает lvalue ссылку — константную или неконстантную. Если же параметр задается rvalue выражением, функция вернет значение, применив при этом move. Преимущество такого подхода — одним выстрелом получается неплохой компромисс между эффективностью и надежностью. Код защищен от опасности возникновения висячих ссылок.

Ну а перегрузки и типовую безопасность придется достигать использованием SFINAE или концептов. И это слабая сторона такого подхода.
--
Отредактировано 18.08.2020 11:54 rg45 . Предыдущая версия . Еще …
Отредактировано 18.08.2020 11:36 rg45 . Предыдущая версия .
Отредактировано 18.08.2020 11:30 rg45 . Предыдущая версия .
Отредактировано 18.08.2020 11:30 rg45 . Предыдущая версия .
Отредактировано 18.08.2020 11:28 rg45 . Предыдущая версия .
Re[8]: Правомерно ли такое
От: B0FEE664  
Дата: 18.08.20 12:32
Оценка:
Здравствуйте, 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> И если арг не проинициализируется от рвелью и не продлит жизнь объекту, он умрет.

Если арг не проинициализируется, то и функция вызвана не будет. Причём тут продление жизни для ссылок?
И каждый день — без права на ошибку...
Re[5]: Правомерно ли такое
От: T4r4sB Россия  
Дата: 18.08.20 15:57
Оценка:
Здравствуйте, rg45, Вы писали:

R>Возможен сценарий получения битой ссылки. При нынешних-то тенденциях максимально широкого использования auto&&:


R>
R>auto&& v = push_back_helper( std::vector<int>(), i );
R>


Собрал я такой код (вернее, скомпилировал в текстовый llvm с O3)

template<typename T>
T& test( T&&t)
{
    return t;
}

struct IntWrapper {
  IntWrapper(int x): x(x) {}
  ~IntWrapper() { x = 1; }
  int getX() { return x; }
  int x;
};

int main()
{
  auto&& i = test(IntWrapper(0));
  return i.getX();
}

Превращается в возврат 1
(((
По коду ссылка не битая, но она указывает на мёртвый объект, у которого уже вызван деструктор
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: Правомерно ли такое
От: rg45 СССР  
Дата: 18.08.20 16:02
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Превращается в возврат 1

TB>(((
TB>По коду ссылка не битая, но она указывает на мёртвый объект, у которого уже вызван деструктор

Так это и есть битая ссылка, раз объект мертвый. Вот эта единица — это просто стековый мусор, значение которого по случайности совпало с оригиналом. Попробуй использовать, например, std::string вместо int — спецэффекты будут поинтереснее.
--
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.