Should I return an rvalue reference parameter by rvalue reference?

前端 未结 4 1766
礼貌的吻别
礼貌的吻别 2020-12-12 22:51

I have a function which modifies std::string& lvalue references in-place, returning a reference to the input parameter:

std::string& tra         


        
4条回答
  •  攒了一身酷
    2020-12-12 23:25

    There's no right answer, but returning by value is safer.

    I have read several questions on SO relating to returning rvalue references, and have come to the conclusion that this is bad practice.

    Returning a reference to a parameter foists a contract upon the caller that either

    1. The parameter cannot be a temporary (which is just what rvalue references represent), or
    2. The return value won't be retained past the the next semicolon in the caller's context (when temporaries get destroyed).

    If the caller passes a temporary and tries to save the result, they get a dangling reference.

    From what I have read, it seems the consensus is that since return values are rvalues, plus taking into account the RVO, just returning by value would be as efficient:

    Returning by value adds a move-construction operation. The cost of this is usually proportional to the size of the object. Whereas returning by reference only requires the machine to ensure that one address is in a register, returning by value requires zeroing a couple pointers in the parameter std::string and putting their values in a new std::string to be returned.

    It's cheap, but nonzero.

    The direction currently taken by the standard library is, somewhat surprisingly, to be fast and unsafe and return the reference. (The only function I know that actually does this is std::get from .) As it happens, I've presented a proposal to the C++ core language committee toward the resolution of this issue, a revision is in the works, and just today I've started investigating implementation. But it's complicated, and not a sure thing.

    std::string transform(std::string&& input)
    {
        return transform(input); // calls the lvalue reference version
    }
    

    The compiler won't generate a move here. If input weren't a reference at all, and you did return input; it would, but it has no reason to believe that transform will return input just because it was a parameter, and it won't deduce ownership from rvalue reference type anyway. (See C++14 §12.8/31-32.)

    You need to do:

    return std::move( transform( input ) );
    

    or equivalently

    transform( input );
    return std::move( input );
    

提交回复
热议问题