R>template <class T>
R>void swap (T& a, T& b)
R>{
R> T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
R>}
R>
to uzhas:
---------
Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move. Я полагаю, если ты выражаешь свое несогласие в виде оценки, то, вероятно, можешь выразить его и на словах? Буду благодарен если объяснишь.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>>>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна. EP>>А как же алгоритмы, например быстрый rotate? EP>>А как же C++11 std::swap в конце концов? R>swap можно можно реализовать при помощи std::forward:
std::forward предназначен для других целей, и очевидно что в этом случае у std::move синтаксис лучше
move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл?
Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
R>>>>Возможно, я ошибаюсь, но у меня такая предубежденность, что при идеальных архитектуре и дизайне move не нужен вовсе. Т.о. move — это просто костыль, частота использования которого может служить мерилом плохого дизайна. EP>>>А как же алгоритмы, например быстрый rotate? EP>>>А как же C++11 std::swap в конце концов? R>>swap можно можно реализовать при помощи std::forward:
EP>std::forward предназначен для других целей, и очевидно что в этом случае у std::move синтаксис лучше
Я в курсе, для чего это предназначалось. Да только кривовато это как-то получилось: функция называется move, хотя на самом деле ничего не перемещает. Я ожидал более весомой аргументации, чем "они хотели как лучше...".
EP>move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл? EP>Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"?
Грубо говоря, да. Хотя бы потому, что и forward, и static_cast приводят меня ровно к тому же результату (rvalue ссылка), при этом они не скрывают от меня сути происходящего за не уместным в данном случае словом 'move'.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move.
оно просто не работает, как если бы это был std::move, потому что именно благодаря std::move можно переместить значение из c в b
внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&. для функции с двумя типами T он будет давать осечки
std::move для меня на пальцах — это автоматизация swap, то есть встроенная в язык фишка для обмена двух переменных (swap) и эта фишка ортогональна качеству дизайна имхо
Здравствуйте, rg45, Вы писали:
EP>>move можно реализовать при помощи раскидывания static_cast по всему коду — а смысл? EP>>Я правильно тебя понимаю, что "move — это просто костыль, буду использовать что угодно, хоть forward, хоть static_cast, но только не его"? R>Грубо говоря, да. Хотя бы потому, что и forward, и static_cast приводят меня ровно к тому же результату (rvalue ссылка), при этом они не скрывают от меня сути происходящего за не уместным в данном случае словом 'move'.
Допустим есть код:
f(std::move(obj));
// Что здесь можно сказать об obj ?
1. obj должен быть destructable
2. если это стандартный тип (либо тип придерживающийся тех же правил), то он:
Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
Это такое же "valid but unspecified state", как и при Basic Exception Safety Guarantee.
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, rg45, Вы писали:
R>>Я действительно не понимаю, что мешает мне в данном случае использовать std::forward вместо std::move.
U>оно просто не работает, как если бы это был std::move, потому что именно благодаря std::move можно переместить значение из c в b U>внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&. для функции с двумя типами T он будет давать осечки
Я тоже приведу кое-какие ссылки — на стандарт C++11:
Здравствуйте, rg45, Вы писали:
R>std::move ничего никуда не перемещает!
я не спорю с этим, возможно, плохо выразился. std::move "создает" rvaluе ref и соответствующие конструкторы типа T уже сделают перемещение
std::forward сможет сделать rvalue ref только при определенных обстоятельствах
R>Что конкретно в нем не так
слишком много копирований
Здравствуйте, uzhas, Вы писали:
U>внутри std::swap обязательно нужно использовать rvalue ref, а std::forward просто прокидывает входящий тип и для того, чтобы он правильно его прокидывал нужно принимать T&&.
В случае rg45 нет "прокидки", и если использовать его swap с type deduction, то там будет rvref.
Но, в примере со swap, разница с обычным move хоть формальная, но есть.
Например, если не использовать type deduction (сферический пример):
#include <iostream>
#include <ostream>
#include <utility>
template<typename T,int> void type_is();
template <int i,class T>
void swap (T& a, T& b)
{
type_is<decltype(std::forward<T>(a)),2*i+1>();
type_is<decltype(std::move(a)),2*i+2>();
T c(std::forward<T>(a)); a=std::forward<T>(b); b=std::forward<T>(c);
}
int main()
{
int a = 1, b = 2;
swap<0>(a, b);
swap<1,int&>(a, b);
std::cout << a << ", " << b << std::endl;
}
Вывод:
Compilation finished with errors:
/tmp/cci7QIMZ.o: In function `main':
source.cpp: ( .text.startup+0x5 ) : undefined reference to `void type_is<int&&, 1>()'
source.cpp: ( .text.startup+0xa ) : undefined reference to `void type_is<int&&, 2>()'
source.cpp: ( .text.startup+0xf ) : undefined reference to `void type_is<int&, 3>()'
source.cpp: ( .text.startup+0x14 ) : undefined reference to `void type_is<int&&, 4>()'
collect2: error: ld returned 1 exit status
Здравствуйте, rg45, Вы писали:
R>>>Что конкретно в нем не так U>>слишком много копирований R>Так-так, это уже интересно. Опыт это подтверждает: R>http://liveworkspace.org/code/3Mun0g$13. R>Я, правда, пока еще не понял, откуда они берутся (с учетом того, что std::forward возвращет rvalue reference), буду разбираться, но все равно спасибо.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
R>>>>Что конкретно в нем не так U>>>слишком много копирований R>>Так-так, это уже интересно. Опыт это подтверждает: R>>http://liveworkspace.org/code/3Mun0g$13. R>>Я, правда, пока еще не понял, откуда они берутся (с учетом того, что std::forward возвращет rvalue reference), буду разбираться, но все равно спасибо.
EP>Нужен move assignment:
EP>
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, rg45, Вы писали:
R>>std::move ничего никуда не перемещает! U>я не спорю с этим, возможно, плохо выразился. std::move "создает" rvaluе ref и соответствующие конструкторы типа T уже сделают перемещение U>std::forward сможет сделать rvalue ref только при определенных обстоятельствах
R>>Что конкретно в нем не так U>слишком много копирований
EP>2. move использует type-deduction, ему не нужно явно передавать тип
Ну это уже проблема второго порядка. Она и так-то не очень критична, кроме того может быть тривиально решена как на уровне пользователя, так и на уровне стандарта. То, что std::forward не сбивает с толку неподходящим названием, ИМХО, гораздо важнее.
--
Справедливость выше закона. А человечность выше справедливости.
R>Здравствуйте, uzhas, Вы писали:
R>>>Что конкретно в нем не так U>>слишком много копирований
R>Итак, продолжаем разговор. Копирований здесь нет вовсе: http://liveworkspace.org/code/4oRZSF$0. R>Есть что возразить?
Здравствуйте, rg45, Вы писали:
EP>>Если сравнивать с "forward как move", то EP>>1. move всегда возвращает rvref
R>std::forward тоже всегда возвращает rvref: R>
#include <utility>
template<typename T> void type_is();
int main()
{
int a;
type_is<decltype(std::forward<int>(a))>();
type_is<decltype(std::forward<int&>(a))>();
}
Compilation finished with errors:
/tmp/cceig6tw.o: In function `main':
source.cpp: (.text.startup+0x5): undefined reference to `void type_is<int&&>()'
source.cpp: (.text.startup+0xa): undefined reference to `void type_is<int&>()'
collect2: error: ld returned 1 exit status