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;
return x;
}
void bar() {
sometype & a = foo();//Binding r-value to l-value reference is non-standard Microsoft C++ extension
sometype && b = foo(); //ok
}
Questions:
What's wrong with sometype & a = foo();
? isn't the return value from foo()
an lvalue and a
is also an lvalue?
Is sometype && b = foo();
actually rvalue reference? Does it "steal" the return value from foo()
and send what was in b
to the destructor?
Is there another way to not have this warning?
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().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With