c++c++17rvo

Return Value Optimization: Explicit move or implicit?


I have a function like this, do i have to explicitly use move here or it is implicit?

std::vector<int> makeVector();
std::vector<int> makeVector2();

std::optional<std::vector<int>> getVectOr(int i) {
  if(i==1) {
    std::vector<int> v = makeVector();
    return std::move(v);
  }
  else if(i==2) {
    std::vector<int> v2 = makeVector2();
    return std::move(v2);
  }
  return std::nullopt;
}


Solution

  • It doesn't matter whether you use std::move or not. No return value optimization will take place here. There are several requirements for RVO to take place.

    One of the requirements for return value optimization is that the value being returned must be the same type as what the function returns.

    std::optional<std::vector<int>> getVectOr(int i)
    

    Your function returns std::optional<std::vector<int>>, so only a copy of a temporary of the same type will get elided. In the two return statements in question here, both temporaries are std::vector<int>s which are, of course, not the same type, so RVO ain't happening.

    No matter what happens, you're returning std::optional<std::vector<int>>. That's an absolute requirement here. No exceptions. But your adventure to return something from this function always starts with std::vector<int>. No matter what you try, you can't turn it into a completely different type. Something will have to get constructed somewhere along the way. No return value optimization.

    But having said that: there are also move semantics that come here into play. If the stars get fortunately aligned for you (and this is very likely) move semantics will allow for everything to happen without copying the contents of the large vector around. So, although no return value optimization takes place, you may win the lottery and have everything to happen without shuffling the actual contents of the vector across all your RAM. You can use your debugger, yourself, to confirm or deny whether you've won the lottery on that account.

    You may also have a possibility of the other type of RVO, namely returning a non-volatile auto-scoped object from the function:

    std::optional<std::vector<int>> getVectOr(int i) {
    
        std::optional<std::vector<int>> ret;
    
        // Some code
    
        return ret;
     }
    

    It's also possible for return value optimization to take place here as well, it is optional but not mandatory.