了解警告:将r值绑定到l值引用

shi*_*zou 8 c++ syntax resharper rvalue c++11

我想通过引用传递一个struct,因此它不会被复制,但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
}
Run Code Online (Sandbox Code Playgroud)

问题:

怎么了sometype & a = foo();?是不是foo()左值的返回值,a也是左值?

sometype && b = foo();实际上右值引用?它是否"窃取"返回值foo()并将结果发送b给析构函数?

还有另一种方法没有这个警告吗?

Ric*_*ges 12

您正在引用临时对象.唯一合法的方法是:

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

object&& (可变r值参考)

这是(故意的)语言限制.

进一步讨论:

将临时值分配给引用会延长临时的生命周期,以使其与引用的生命周期相匹配.因此,令许多初学者惊讶的是,这是合法的:

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

但是,对临时引用可变引用通常是一个逻辑错误,因此在语言中不允许这样做:

{
  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.
Run Code Online (Sandbox Code Playgroud)

这是一个更现实的原因,为什么它可能是一个逻辑错误,给出:

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
Run Code Online (Sandbox Code Playgroud)

你必须用上面的代替:

  string s = foo();
  s += "bar";
  // do something here with s
Run Code Online (Sandbox Code Playgroud)

请注意,在命名变量(l值)中捕获临时值没有任何开销.

r值引用被设计为移动构造函数或移动赋值的主题.因此,它们是可变的是有意义的.它们的本质意味着物体是瞬态的.

因此,这是合法的:

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

它可能会帮助您记住,指定&&您断言您知道该变量是一个可变的临时变量.

但它允许的真正原因是这样可以工作:

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));
Run Code Online (Sandbox Code Playgroud)

在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().
Run Code Online (Sandbox Code Playgroud)

  • 最初的想法是对临时文件进行可变引用是没有意义的,因为临时文件会被丢弃。在临时对象上调用可变方法通常是一个逻辑错误,因此是不允许的。指定 r 值参考信号本质上表明您知道自己在做什么。 (2认同)

mar*_*inj 5

sometype & a = foo(); 有什么问题??

foo() 返回临时值,因此您无法将其绑定到引用,因为在完整表达式(赋值行)结束后它将不再存在。延长其生命周期的唯一方法是将其更改为const sometype & a = foo();或将其分配给右值引用。

是某种类型 && b = foo(); 实际上是右值引用?

是(阅读此处了解更多信息:右值引用允许悬空引用吗?

它是否“窃取”了 foo() 的返回值并将 b 中的内容发送给析构函数?

不,它会延长使用寿命

有没有另一种方法可以没有这个警告?

您有三个选择:(1) 分配给右值引用,(2) 分配给 const 左值引用,(3) 按值返回但在您的类中实现移动语义。

您还可以指望编译器将对返回值执行 RVO。