理解警告:将r值绑定到l值引用
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()
的返回值不是左值,a
也是左值吗?
sometype && b = foo();
实际上是右值引用吗?它是否"窃取"foo()
的返回值,并将b
中的内容发送到析构函数?
有没有其他方法可以不发出警告?
您正在引用一个临时对象。唯一合法的方法是:
const object&
(常量l值参考)或
object&&
(可变r值参考)
这是一种(故意的)语言限制。
进一步讨论:
将临时对象分配给引用会延长临时对象的生存期,使其与引用的生存期相匹配。因此,令许多初学者惊讶的是,这是合法的:
{
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
请注意,在命名变量(l-value)中捕获临时变量没有任何开销。
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().
sometype&a=foo()?
foo()返回临时,因此您无法将其绑定到引用,因为它在完整表达式(赋值行)结束后将不再存在。延长其使用寿命的唯一方法是将其更改为const sometype & a = foo();
或将其分配给右值引用。
是sometype&;b=foo();真的重新估价参考?
是的(阅读这里了解更多:右值引用允许悬挂引用吗?)
它是否"窃取"了foo()的返回值,并将b中的内容发送到析构函数?
不,它延长了的使用寿命
有没有其他方法可以不发出警告?
您有三种选择:(1)分配给右值引用,(2)分配给常量左值引用,以及(3)按值返回,但在类中实现移动语义。
您也可以指望编译器会对返回的值执行RVO。
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 将常量指针引用绑定到非常量指针
- 运行时错误:引用绑定到类型为"int"的空指针
- 了解C++如何返回引用并绑定到引用
- 模板允许左值与右值引用绑定
- 为什么结构化绑定不使用"auto&"返回对结构成员的引用,而是返回成员本身
- 运行时错误:引用绑定到类型"int"的未对齐地址0xbebebebebebebec6,这需要 4 个字节对齐 (stl_vector.h)
- 无法将类型"T&"的非常量左值引用绑定到类型"T"的右值 t++ std::atomic<T>
- C++通过绑定到引用成员而缩短临时变量寿命?
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- 在其他容器中使用 boost::container::static_vector 时,GCC 编译错误"将'const s'绑定到类型's&'的引用丢弃限定符"
- 为什么定义复制构造函数会给我错误:无法将类型 'obj&' 的非常量左值引用绑定到类型为"obj"的右值?
- 对结构成员的临时绑定引用
- 错误:在类型 "blah blah" 的绑定引用中删除限定符以初始化"some other blah blah"
- 为什么我可以在初始化引用后重新绑定引用?
- 为什么按引用传入会导致绑定引用类型错误
- 返回非常量引用会导致绑定引用错误
- 递归到迭代而不重新绑定引用
- 类型绑定引用中的限定符和 const 类型的初始值设定项中删除
- 为什么C++不允许重新绑定引用?