16

I have a code that operates on a vector:

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

For normal push_back, do I need to use forward(value), move(value) or just value (according to new C++11) ? and how do they impact the performance?

For example,

v.push_back(forward<T>(value));
Nawaz
  • 353,942
  • 115
  • 666
  • 851
SwiftMango
  • 15,092
  • 13
  • 71
  • 136
  • `v.emplace_back(std::forward(value))`. If you `move`, you might end up moving from an lvalue (since the `T&&` in this case makes it a *universal reference* that can bind to both rvalues and lvalues) – Praetorian Aug 13 '13 at 16:35
  • @Praetorian push_back provides a signature that takes rvalue reference too: `void push_back (value_type&& val);` So it should work in the same way as `emplace_back(forward)` right? – SwiftMango Aug 13 '13 at 16:37
  • @texasbruce It does, but `emplace_back` forwards the arguments to the constructor and constructs the object in place. In this case it makes no difference since the element you're adding is the same as the vector's `value_type`, but if it weren't `push_back` would create a temporary from the value and then move it (this shouldn't make much of a difference though) – Praetorian Aug 13 '13 at 16:40
  • 1
    possible duplicate of [Do I use std::forward or std::move here?](http://stackoverflow.com/questions/17355521/do-i-use-stdforward-or-stdmove-here) – user541686 Aug 13 '13 at 16:40
  • This article might be good: http://www.codeproject.com/Articles/397492/Move-Semantics-and-Perfect-Forwarding-in-Cplusplus. – taocp Aug 13 '13 at 16:42
  • @Mehrdad I believe I am asking for a specific case, not quite a dup? – SwiftMango Aug 13 '13 at 16:44
  • @texasbruce: Hmm yeah actually I'm not sure anymore... it's similar in some ways but not quite the same. Sorry about that. :\ – user541686 Aug 13 '13 at 16:46

4 Answers4

18

The current code will not compile when the second argument is lvalue because T&& will turn out to be X& which means T needs to be X& which in turn means std::vector<T> will become std::vector<X&> which will NOT match the first argument which is std::vector<X> &. Hence, it is an error.

I would use two template parameters:

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

Since V could a different type from T, so emplace_back makes more sense, because not only it solves the problem, it makes the code more generic. :-)

Now the next improvement : since we're using emplace_back which creates the object of type T from argument value (possibly using constructor), we could take advantage of this fact, and make it variadic function:

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

That is even more generic, as you could use it as:

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

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

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

Hope that helps.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Your answer is well explained but aren't you essentially writing a useless wrapper for emplace_back – aaronman Aug 13 '13 at 21:07
  • 1
    @aaronman: Look at the original question. In that there are some ... comments which imply some other work might be done either side of the push_back. They just aren't present here but I don't think that matters. –  Aug 14 '13 at 05:48
  • @BleepBloop sorry my mistake – aaronman Aug 14 '13 at 05:49
  • 1
    @aaronman: This answer answers the original question, with some additional opportunities. If he doesn't need the additional opportunities, he can ignore them. – Nawaz Aug 14 '13 at 05:51
  • 1
    +1 for the wrapper around the emplace_back, providing more in depth possibilities ... btw you must love how c++11 make things easy :( – Avi Aug 30 '17 at 18:36
7
  1. forward(value) is used if you need perfect forwarding meaning, preserving things like l-value, r-value.

  2. forwarding is very useful because it can help you avoid writing multiple overloads for functions where there are different combinations of l-val, r-val and reference arguments

  3. move(value) is actually a type of casting operator that casts an l-value to an r-value

  4. In terms of performances both avoid making extra copies of objects which is the main benefit.

So they really do two different things


When you say normal push_back, I'm not sure what you mean, here are the two signatures.

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

the first one you can just pass any normal l-val, but for the second you would have to "move" an l-val or forward an r-val. Keep in mind once you move the l-val you cannot use it

For a bonus here is a resource that seems to explain the concept of r-val-refs and other concepts associated with them very well.

As others have suggested you could also switch to using emplace back since it actually perfect forwards the arguments to the constructor of the objects meaning you can pass it whatever you want.

aaronman
  • 18,343
  • 7
  • 63
  • 78
6
  • When passing a parameter that's a forwarding reference, always use std::forward.
  • When passing a parameter that's an r-value, use std::move.

E.g.

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.
}

Here's an excellent video by Scott Meyers explaining forwarding references (which he calls universal references) and when to use perfect forwarding and/or std::move:

C++ and Beyond 2012: Scott Meyers - Universal References in C++11

Also see this related question for more info about using std::forward: Advantages of using forward

Community
  • 1
  • 1
Felix Glas
  • 15,065
  • 7
  • 53
  • 82
0

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

That video, IMO, has the best explanation of when to use std::forward and when to use std::move. It presents the idea of a Universal Reference which is IMO an extremely useful tool for reasoning about move semantics.

Jake
  • 747
  • 1
  • 5
  • 19