Напред или Преместване

Това валидна употреба ли е на движение и напред?
Еднакви ли са f3 и f4?
Опасно ли е да го правите?
Благодаря ви!

#include <utility>
class A {};
A f1() {
  A a;
  return a;   // Move constructor is called
}
A f2(A&& a) {
  return a;   // Copy constructor is called, which is what I try to avoid.
}
A f3(A&& a) {
  return std::forward<A&&>(a); // Move constructor is called
}
A f4(A&& a) {
  return std::move(a); // Move constructor is called
}

person yufanyufan    schedule 15.04.2013    source източник


Отговори (3)


  • Използвайте std::forward с универсална препратка, т.е. template <typename T> ... T&&.

  • Използвайте std::move с препратка към rvalue (като вашия A&&).

Така че и f1, и f4 са правдоподобни решения. Те правят различни неща, така че трябва да решите кое искате.

Не използвайте f2 или f3.

person Kerrek SB    schedule 15.04.2013

std::forward съществува поради странност в начина, по който && работи при дедукция на типа.

При дедукция на типа, T в T&& ще се свърже с една от 3 възможности. Ако се изведе от lvalue int&, T ще се свърже с int&. Тогава int& && е просто int&. Ако се изведе от lvalue int const&, T ще се свърже с int const&, а int const& && е int const&. Ако се изведе от rvalue int от някакъв вид, T ще се свърже с int, а int&& е int&&.

std::forward е помощна функция за обръщане на тази карта. Трите уместни подписа на std::forward<> са: T& std::forward<T&>(T&) или T const& std::forward<T const&>(T const&) или T&& std::forward<T>(T&&)

Всичко това в крайна сметка се оказва изключително полезно, когато изпълнявате техниката, известна като „перфектно препращане“, където използвате T&&t в контекст на извеждане на типа, след това std::forward<T>(t), за да предадете „същия тип“, от който е изведен, към друго повикване.

Имайте предвид, че има няколко опростяващи лъжи по-горе. Съществува и възможност за T const&&, което е доста неясно като тип, като пример. Вероятно съм премълчал някои подробности за това как работи дедукцията на типа и термините rvalue и lvalue не отразяват напълно пълните 5-кратни (или 6?) различни видове стойности на променливи в C++11.

person Yakk - Adam Nevraumont    schedule 15.04.2013

За вашия пример те ще направят същото, но е идиоматично да се използва std::move

A f(A&& a) {
  // use std::move(a)
}

Малко по-различен е случаят с шаблоните за функции

template<typename A>
A f(A&& a) {
   // use std::forward<A>(a)
}

Разликата е, че втората версия може да получава както lvalues, така и rvalues ​​(Scott Meyers ги нарече "универсални препратки"), докато първата версия може да получава само rvalues.

person TemplateRex    schedule 15.04.2013