Когда следует использовать форвард и двигаться?

У меня есть код, который работает с вектором:

template<typename T>
void doVector(vector<T>& v, T&& value) {
    //....
    v.push_back(value);
    //...
}

Для обычного push_back нужно ли использовать forward(value), move(value) или просто value (согласно новому С++ 11)? и как они влияют на производительность?

Например,

v.push_back(forward<T>(value));

Ответы

Ответ 1

Текущий код не будет компилироваться, если второй аргумент равен lvalue, потому что T&& окажется X&, что означает T должно быть X&, что в свою очередь означает, что std::vector<T> станет std::vector<X&> который не будет соответствовать первому аргументу, который равен std::vector<X> &. Следовательно, это ошибка.

Я бы использовал два параметра шаблона:

template<typename T, typename V>
void doVector(vector<T> & v, V && value) 
{
    v.emplace_back(std::forward<V>(value));
}

Так как V может быть другого типа из T, поэтому emplace_back имеет больше смысла, потому что не только он решает проблему, но и делает код более общим.: -)

Теперь следующее улучшение: поскольку мы используем emplace_back, который создает объект типа T из аргумента value (возможно, используя конструктор), мы могли бы воспользоваться этим фактом и сделать его вариационной функцией:

template<typename T, typename ...V>
void doVector(vector<T> & v, V && ... value) 
{
    v.emplace_back(std::forward<V>(value)...);
}

Это еще более общее, поскольку вы можете использовать его как:

struct point
{
    point(int, int) {}
};

std::vector<point> pts;
doVector(pts, 1, 2);

std::vector<int> ints;
doVector(ints, 10);

Надеюсь, что это поможет.

Ответ 2

  • forward(value) используется, если вам нужно совершенное значение пересылки, сохраняя такие вещи, как l-value, r-value.

  • пересылка очень полезна, потому что она может помочь вам избежать написания нескольких перегрузок для функций, где существуют различные комбинации l-val, r-val и ссылочных аргументов

  • move(value) на самом деле является типом оператора литья, который передает значение l в значение r

  • С точки зрения производительности, избегайте создания дополнительных копий объектов, которые являются основным преимуществом.

Таким образом, они действительно выполняют две разные вещи.


Когда вы говорите обычный push_back, я не уверен, что вы имеете в виду, вот две подписи.

void push_back( const T& value );
void push_back( T&& value );

первый, вы можете просто передать любой нормальный l-val, но для второго вам придется "переместить" l-val или переслать r-val. Имейте в виду, как только вы перемещаете l-val, вы не можете его использовать.

Для бонуса здесь есть ресурс, который, по-видимому, очень хорошо объясняет концепцию r-val-refs и других понятий, связанных с ними.

Как и другие, вы также можете переключиться на использование emplace, поскольку он действительно идеально подходит для аргументов конструктора объектов, что означает, что вы можете передать его, как хотите.

Ответ 3

  • При передаче параметра ссылка на пересылку всегда используйте std::forward.
  • При передаче параметра, имеющего значение r, используйте std::move.

например.

template <typename T>
void funcA(T&& t) {
    funcC(std::forward<T>(t)); // T is deduced and therefore T&& means forward-ref.
}

void funcB(Foo&& f) {
    funcC(std::move(f)); // f is r-value, use move.
}

Здесь отличное видео Скотта Мейерса, объясняющего пересылку ссылок (которые он называет универсальными ссылками), и когда использовать идеальную пересылку и/или std::move:

С++ и Beyond 2012: Скотт Майерс - Универсальные ссылки в С++ 11

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

Ответ 4

http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11

В этом видео, IMO, есть лучшее объяснение того, когда следует использовать std:: forward и когда использовать std:: move. В нем представлена ​​идея универсальной ссылки, которая является ИМО чрезвычайно полезным инструментом для рассуждения о семантике перемещения.