简体   繁体   中英

C++ lvalues, rvalues, references, parameters, and performance

So I have a function that needs to take an std::vector as a parameter. I'd like to know the best way to declare the parameter so that the underlying array is not deep-copied, as it could be rather large.

// which should I choose?
void myFunc(std::vector<char>); // 1
void myFunc(std::vector<char>&); // 2
void myFunc(std::vector<char>&&);  // 3
void myFunc(std::vector<char>*) // 4

Which should I choose? Also, I won't be modifying the vector in the function so shouldn't I add const? Should I overload the function and have a combination of these?

  1. If you are going to make a copy of it inside the function anyway:

     void myFunc(std::vector<char>); 
  2. If you just want to read the argument without copying it:

     void myFunc(const std::vector<char>&); 
  3. If you want to modify the original vector passed to the function:

     void myFunc(std::vector<char>&); 
  4. If you want to optimize for rvalues or if you want to move the argument into the function:

     void myFunc(std::vector<char>&&); 
  5. If you need to be able to signify an optional argument passed by reference:

     void myFunc(const std::vector<char>*); 
  6. If you need to pass an optional argument that you want to modify if non- nullptr :

     void myFunc(std::vector<char>*); 

If you don't want to deep copy std::vector :

  • move it into your function:

     // foo() decalaration void foo(std::vector<int> v); // usage example std::vector<int> v {0, 1, 2, 3}; foo(std::move(v)); // v is moved into foo() and invalid now 

    You may also return this vector from function in the same manner:

     // foo() decalaration std::vector<int> foo(std::vector<int> v) { return v.push_back(4), std::move(v); } // usage example std::vector<int> v {0, 1, 2, 3}; v = foo(std::move(v)); // now v is {0, 1, 2, 3, 4} and no one were deep copied 

    But note if you don't move it (call foo(v) instead of foo(std::move(v)) ) then it will be deep copied . Under the hood, parameter v of foo() is just constructed by move-constructor .

  • pass it as reference:

     // foo() declaration void foo(std::vector<int>& v); 

    But now we have a problem: which reference and cv-qualifiers ? Well, in general we have 2 types of references and 4 types of cv-qualifiers , altogether 8 declarations:

     void foo(std::vector<int>&); void foo(std::vector<int> const&); void foo(std::vector<int> volatile&); void foo(std::vector<int> const volatile&); void foo(std::vector<int>&&); void foo(std::vector<int> const&&); void foo(std::vector<int> volatile&&); void foo(std::vector<int> const volatile&&); 

    Of course, part of them are useless and should be deleted. But nevertheless too much declarations also known as perfect forwarding problem (actually, there were no rvalue-references when it was a problem so the problem was 2 times smaller).

    For example, if you want to modify v you need 2 functions at least:

     void foo(std::vector<int>&); void foo(std::vector<int>&&); 

    In this case you will be able to call foo() on lvalue objects:

     std::vector<int> v; foo(v); 

    as well as on temporary:

     foo(std::vector<int>{1, 2, 3, 4, 5}); 

    But how to code just one implementation for different reference types and / or cv-qualifiers? Let me introduce universal references :

     template<typename Vector> void foo(Vector&& v); 

    Vector&& is always a reference type and may be deduced into

    • std::vector<int>& if you pass lvalue of type std::vector<int> into foo() :

       std::vector<int> v; foo(v); // v is lvalue 
    • std::vector<int> const& if you pass const lvalue of type std::vector<int> :

       std::vector<int> const v; foo(v); // v is const lvalue 
    • std::vector<int>&& if you pass rvalue:

       foo(std::vector<int>{0, 1, 2}); // v is rvalue 
    • etc...

    But in this case you have to check acceptance of type Vector . But that is another story.

And I definitely find no sense to pass pointers instead of references in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM