Understanding the warning: binding r-value to l-value reference

后端 未结 2 1958
走了就别回头了
走了就别回头了 2020-12-16 19:05

I want to pass a struct by reference so it won\'t be copied, but Resharper is giving the warning below:

struct sometype {
};

sometype foo() {
    sometype x         


        
2条回答
  •  时光取名叫无心
    2020-12-16 19:52

    You are taking a reference to a temporary object. The only legal way to do this is either :

    const object& (const l-value reference), or

    object&& (mutable r-value reference)

    This is a (deliberate) language limitation.

    further discussion:

    Assigning a temporary to a reference extends the lifetime of the temporary so that it matches the lifetime of the reference. Therefore, surprisingly to many beginners, this is legal:

    {
      const string& s = foo();
      cout << s << endl;         // the temporary to which s refers is still alive
    }
    // but now it's destroyed
    

    However, it would normally be a logic error to take a mutable reference to a temporary so this is disallowed in the language:

    {
      string s& = foo();  // this is not possible
      s += "bar";         // therefore neither is this
      // the implication is that since you modified s, you probably want to
      // preserve it
    }
    // ... but now it's destroyed and you did nothing with it.
    

    here's a more realistic reason why it's probably a logic error, given:

    string foo();         // function returning a string
    void bar(string& s);  // this function is asserting that it intends to *modify*
                          // the string you sent it
    
    // therefore:
    
    bar(foo());           // makes no sense. bar is modifying a string that will be discarded.
                          // therefore assumed to be a logic error
    

    you would have to replace the above with:

      string s = foo();
      s += "bar";
      // do something here with s
    

    Note that there is no overhead whatsoever for capturing the temporary in a named variable (l-value).

    r-value references are designed to be the subject of a move-constructor or move-assignment. Therefore it makes sense that they are mutable. Their very nature implies that the object is transient.

    thus, this is legal:

    string&& s = foo();    // extends lifetime as before
    s += "bar";
    baz(std::move(s));     // move the temporary into the baz function.
    

    It might help you to remember that specifying && is you asserting that you know that the variable is a mutable temporary.

    But the real reason it's allowed is so that this will work:

    string foo();   // function that returns a string
    void bar(string&& s);  // function that takes ownership of s
    
    bar(foo());  // get a string from foo and move it into bar
    
    // or more verbosely:
    
    string s = foo();
    bar(move(s));
    

    prior to c++11, bar would have to have been written one of these ways:

    void bar(string s);   // copy a string
    
    // resulting in:
    
    const string& s = foo();
    bar(s);  // extra redundant copy made here
    
    void bar(const string& s); // const l-value reference - we *may* copy it
    // resulting in:
    
    const string& s = foo();
    bar(s);  // maybe an extra redundant copy made here, it's up to bar().
    

提交回复
热议问题