Move semantics and perfect forwarding difference

前端 未结 2 790

I already got what move semantics is from this question: What are move semantics?

But I still do not get what perfect forwarding is in relation to move semantics.

2条回答
  •  感动是毒
    2020-12-31 16:36

    Dealing with r-value references and reference collapsing can be more complex than it initially appears.

    Perfect forwarding

    Perfect forwarding is there to ensure that the argument provided to a function is forwarded (passed) to another function with the same value category (basically r-value vs l-value) as originally provided.

    It is typically used with template functions where reference collapsing may have taken place.

    It can also be used within the same function.

    Scott Meyers gives the following pseudo code in his Going Native 2013 presentation to explain the workings of std::forward (at approximately the 20 minute mark);

    template 
    T&& forward(T&& param) { // T&& here is formulated to disallow type deduction
      if (is_lvalue_reference::value) {
        return param; // return type T&& collapses to T& in this case
      }
      else {
        return move(param);
      }
    }
    

    Example

    An example from the site above, an archetypical example is that of make_unique

    template
    std::unique_ptr make_unique(U&&... u)
    {
        return std::unique_ptr(new T(std::forward(u)...));
    }
    

    In the example, the arguments for the unique_ptr are provided to it through the make_unique as if they had been provided directly to unique_ptr, i.e. the reference, l-value and r-value nature of the arguments are maintained.

    A more concrete example;

    #include 
    #include 
    #include 
    
    struct A {
      // implementation excluded
    };
    
    struct B {
      B(A &) // ctor 1
      {
        std::cout << "ctor 1" << std::endl;
      }
      B(A&&) // ctor 2
      {
        std::cout << "ctor 2" << std::endl;
      }
    };
    
    int main()
    {
      A a;
      auto b1 = std::make_unique(a); // ctor 1 is used
      auto b2 = std::make_unique(A()); // ctor 2 is used
    }
    

    In Brief

    Perfect forwarding depends on a handful of fundamental language constructs new to C++11 that form the bases for much of what we now see in generic programming:

    • Reference collapsing
    • Rvalue references
    • Move semantics

    The use of std::forward is currently intended in the formulaic std::forward, understanding how std::forward works helps understand why this is such, and also aids in identifying non-idiomatic or incorrect use of rvalues, reference collapsing and ilk.

    Thomas Becker provides a nice, but dense write up on the perfect forwarding problem and solution.

提交回复
热议问题