В чем разница между std:: move и std:: forward



Я видел это здесь:
Конструктор перемещения вызов базового класса конструктор перемещения



может кто-нибудь объяснить:




  1. разницу между std::move и std::forward, желательно с примерами кода?

  2. как думать об этом легко, а когда следует использовать

699   3  

3 ответов:

std::move принимает объект и позволяет рассматривать его как временный (rvalue). Хотя это не семантическое требование, обычно функция, принимающая ссылку на rvalue, делает ее недействительной. Когда вы видите std::move, это означает, что значение объекта не должно использоваться впоследствии, но вы все равно можете назначить новое значение и продолжить его использование.

std::forward имеет один вариант использования: чтобы привести шаблонный параметр функции (внутри функции) к категории значений (lvalue или rvalue) вызывающий объект, используемый для его передачи. Это позволяет аргументы rvalue быть принят в качестве правосторонние значения, и значения lvalue быть принят в качестве значения lvalue, схема называется "совершенной прямой."

до иллюстрации:

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

как упоминает Говард, есть также сходства, поскольку обе эти функции просто приводят к ссылочному типу. Но за пределами этих конкретных случаев использования (которые охватывают 99,9% полезности ссылок rvalue) вы должны использовать static_cast напрямую и написать хорошее объяснение того, что вы делаете.

и std::forward и std::move не бросает.

X x;
std::move(x);

выше приведено выражение lvalue x типа X к выражению rvalue типа X (xvalue, чтобы быть точным). move также может принимать значение rvalue:

std::move(make_X());

и в этом случае это функция идентификации: принимает rvalue типа X и возвращает rvalue типа X.

С std::forward вы можете выбрать пункт назначения в какой-то степени:

X x;
std::forward<Y>(x);

бросает именующее выражение x типа X к выражению типа Y. существуют ограничения на то, что Y может быть.

Y может быть доступной базой X, или ссылкой на базу X. Y может быть X, или ссылкой на X. нельзя отбрасывать CV-квалификаторы с forward, но можно добавить cv-квалификаторы. Y не может быть типом, который просто конвертируется из X, за исключением доступного базового преобразования.

если Y является ссылкой lvalue, результатом будет выражение lvalue. Если Y не является ссылкой lvalue, результатом будет выражение rvalue (xvalue, чтобы быть точным).

forward может принимать аргумент rvalue только в том случае, если Y не является ссылкой lvalue. То есть, вы не можете привести rvalue к lvalue. Это делается по соображениям безопасности, поскольку это обычно приводит к висячим ссылкам. Но приведение rvalue к rvalue в порядке и разрешено.

если вы попытаетесь указать Y для чего-то, что не разрешено, ошибка будет поймана во время компиляции, а не запуска время.

std::forward используется вперед параметр точно так же, как он был передан функции. Как показано здесь:

когда использовать аргументы std::forward to forward?

используя std::move предлагает объект в качестве rvalue, чтобы, возможно, соответствовать конструктору перемещения или функции, принимающей rvalues. Он делает это для std::move(x) даже если x не является rvalue само по себе.

Comments

    Ничего не найдено.