Using of rvalue references in c++11

前端 未结 4 1081
渐次进展
渐次进展 2020-12-17 21:18

I would like to implement a function that fills up a vector and then returns an rvalue reference. I tired something like:

std::vector &&fi         


        
相关标签:
4条回答
  • 2020-12-17 21:47

    If you just remove the && from your function it should work, but it will not be a reference. fill_list() will create a vector and return it. During the return a new vector will be created. The first vector that was created inside fill_list() will be copied to the new vector and then will be destroyed. This is the copy constructor's work.

    0 讨论(0)
  • 2020-12-17 21:50

    For a discussion of rvalue references you can read what Bjarne Stroustrup, the author of C++, has to say about them here:

    http://www2.research.att.com/~bs/C++0xFAQ.html#rval

    Addressing your specific example, the short answer is that due to the Named Return Value Optimization - which is a de facto standard C++ compiler feature even pre-C++11 - if you simply return-by-value the compiler will tie up res and myvec efficiently like you want:

    std::vector<int> fill_list() {
        std::vector<int> res;
        ... do something to fill res ...
        cout << &res << endl; // PRINT POINTER
        return res;
    }
    
    int main(int argc, char **argv) {
         std::vector<int> myvec = fill_list();
         cout << &myvec << endl; // PRINT POINTER
         return 0;
    }
    

    The two "PRINT POINTER" lines will print the same pointer in both cases.

    The vector myvec and the vector res in the above will be the same vector with the same storage. No copy constructor or move constructor will be called. In a sense res and myvec will be two aliases of the same object.

    This is even better than using a move constructor. myvec is constructed and "filled up" in-place.

    The compiler achieves this by compiling the function in an "inplace" mode overlaying an immediate stack position in the callers stack frame with the callees local result variable, and simply leaving it there after the callee returns.

    In this circumstance we say that the constructor has been elided. For more information see here:

    http://en.wikipedia.org/wiki/Return_value_optimization

    In the event that you were assigning the result of fill_list in a non-constructor context, than as a return-by-value results in an xvalue (short for "expiring" value, a type of rvalue), the move assignment operator of the target variable would be given preference if it is available.

    0 讨论(0)
  • 2020-12-17 21:52

    The return statement is an error because you atempt to bind an rvalue reference (the return type) to an lvalue (the vector res). An rvalue reference can only be bound to an rvalue.

    Also, as others already mentioned, returning a local variable when the return type is a reference type is dangerous, because the local object will be destroyed after the return statement, then you get a reference that refers to an invalid object.

    If you want to avoid the copy construction during the return statement, just using a non-reference type might already works due to a feature called copy elision. the vector res in your fill_list function may be directly constructed into the vector myvec in your main function, so no copy or move construction is invoked at all. But this feature is allowed by Standard not required, some copy construction is not omitted in some compiler.

    0 讨论(0)
  • 2020-12-17 22:01

    You seem to be confused as to what an rvalue reference is and how it relates to move semantics.

    First thing's first: && does not mean move. It is nothing more than a special reference type. It is still a reference. It is not a value; it is not a moved value; it is a reference to a value. Which means it has all of the limitations of a reference type. Notably, it must refer to a value that still exists. So returning a dangling r-value reference is no better than returning a dangling l-value reference.

    "Moving" is the process of having one object claim ownership of the contents of another object. R-value references facilitate move semantics, but simply having a && does not mean anything has moved. Movement only happens when a move constructor (or move assignment operator) is called; unless one of those two things is called, no movement has occurred.

    If you wish to move the contents of a std::vector out of your function to the user, you simply do this:

    std::vector<int> fill_list() {
      std::vector<int> res;
      ... do something to fill res ...
      return res;
    }
    

    Given this usage of fill_list():

    std::vector<int> myvec = fill_list();
    

    One of two things will happen. Either the return will be elided, which means that no copying or moving happens. res is constructed directly into myvec. Or res will be moved into the return value, which will then perform move-initialization of myvec. So again, no copying.

    If you had this:

    std::vector<int> myvec;
    myvec = fill_list();
    

    Then again, it would be moved into. No copying.

    C++11 knows when it's safe to implicitly move things. Returning a value by value rather than by reference or something is always a safe time to move. Therefore, it will move.

    0 讨论(0)
提交回复
热议问题