了解警告:将右值绑定到左值引用
Understanding the warning: binding r-value to l-value reference
我想通过引用传递一个结构,这样它就不会被复制,但 Resharper 发出以下警告:
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
}
问题:
sometype & a = foo();
怎么了? foo()
中的 return 值不是左值并且 a
不是左值吗?
sometype && b = foo();
实际上是右值引用吗?它是否 "steal" 来自 foo()
的 return 值并将 b
中的内容发送到析构函数?
有没有其他方法可以不出现这个警告?
您正在引用一个临时对象。唯一合法的方法是:
const object&
(常量左值引用),或
object&&
(可变右值引用)
这是(故意的)语言限制。
进一步讨论:
将临时对象分配给引用可延长临时对象的生命周期,使其与引用的生命周期相匹配。因此,令许多初学者惊讶的是,这是合法的:
{
const string& s = foo();
cout << s << endl; // the temporary to which s refers is still alive
}
// but now it's destroyed
但是,对临时对象进行可变引用通常是一个逻辑错误,因此这在语言中是不允许的:
{
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.
这可能是一个逻辑错误的更现实的原因,给出:
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
你必须将上面的替换为:
string s = foo();
s += "bar";
// do something here with s
请注意,在命名变量(左值)中捕获临时变量没有任何开销。
r 值引用被设计为移动构造函数或移动赋值的主题。因此,它们是可变的是有道理的。它们的本质意味着对象是短暂的。
因此,这是合法的:
string&& s = foo(); // extends lifetime as before
s += "bar";
baz(std::move(s)); // move the temporary into the baz function.
它可能会帮助您记住指定 &&
是您断言您 知道 该变量是一个可变的临时变量。
但它被允许的真正原因是它会起作用:
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));
在 c++11 之前,bar 必须以下列方式之一编写:
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().
What's wrong with sometype & a = foo(); ?
foo() return 是临时的,所以你不能将它绑定到引用,因为它在完整表达式(赋值行)结束后将不再存在。延长其生命周期的唯一方法是将其更改为 const sometype & a = foo();
或将其分配给右值引用。
Is sometype && b = foo(); actually rvalue reference?
是(阅读此处了解更多信息:Do rvalue references allow dangling references?)
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?
您有三个选择:(1) 分配给右值引用,(2) 分配给 const 左值引用,(3) return 按值但在 class 中实现移动语义。
您还可以指望编译器将对 returned 值执行 RVO。
我想通过引用传递一个结构,这样它就不会被复制,但 Resharper 发出以下警告:
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
}
问题:
sometype & a = foo();
怎么了? foo()
中的 return 值不是左值并且 a
不是左值吗?
sometype && b = foo();
实际上是右值引用吗?它是否 "steal" 来自 foo()
的 return 值并将 b
中的内容发送到析构函数?
有没有其他方法可以不出现这个警告?
您正在引用一个临时对象。唯一合法的方法是:
const object&
(常量左值引用),或
object&&
(可变右值引用)
这是(故意的)语言限制。
进一步讨论:
将临时对象分配给引用可延长临时对象的生命周期,使其与引用的生命周期相匹配。因此,令许多初学者惊讶的是,这是合法的:
{
const string& s = foo();
cout << s << endl; // the temporary to which s refers is still alive
}
// but now it's destroyed
但是,对临时对象进行可变引用通常是一个逻辑错误,因此这在语言中是不允许的:
{
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.
这可能是一个逻辑错误的更现实的原因,给出:
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
你必须将上面的替换为:
string s = foo();
s += "bar";
// do something here with s
请注意,在命名变量(左值)中捕获临时变量没有任何开销。
r 值引用被设计为移动构造函数或移动赋值的主题。因此,它们是可变的是有道理的。它们的本质意味着对象是短暂的。
因此,这是合法的:
string&& s = foo(); // extends lifetime as before
s += "bar";
baz(std::move(s)); // move the temporary into the baz function.
它可能会帮助您记住指定 &&
是您断言您 知道 该变量是一个可变的临时变量。
但它被允许的真正原因是它会起作用:
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));
在 c++11 之前,bar 必须以下列方式之一编写:
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().
What's wrong with sometype & a = foo(); ?
foo() return 是临时的,所以你不能将它绑定到引用,因为它在完整表达式(赋值行)结束后将不再存在。延长其生命周期的唯一方法是将其更改为 const sometype & a = foo();
或将其分配给右值引用。
Is sometype && b = foo(); actually rvalue reference?
是(阅读此处了解更多信息:Do rvalue references allow dangling references?)
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?
您有三个选择:(1) 分配给右值引用,(2) 分配给 const 左值引用,(3) return 按值但在 class 中实现移动语义。
您还可以指望编译器将对 returned 值执行 RVO。