c++ 理解警告:将r值绑定到l值参考

hsvhsicv  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(139)

我想通过引用传递一个结构体,这样它就不会被复制,但是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中的内容发送到析构函数?
有没有其他方法可以避免这个警告?

jpfvwuh4

jpfvwuh41#

您正在引用临时对象。唯一法律的的方法是:
const object&(常量左值参考),或
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

注意,在命名变量(左值)中捕获临时变量没有任何开销。
右值引用被设计成移动构造函数或移动赋值函数的主体。因此,它们是可变的是有道理的。它们的本质暗示了对象是 transient 的。
因此,这是法律的的:

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

记住指定&&意味着您Assert您 * 知道 * 该变量是一个可变临时变量,这可能会有所帮助。
但它被允许的真实的原因是这样才能起作用:

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().
7eumitmz

7eumitmz2#

有什么问题吗?type & a = foo();?
foo()返回临时值,所以不能绑定到reference,因为在完整表达式结束后(赋值行)它将不再存在,延长其生存期的唯一方法是将其改为const sometype & a = foo();或赋值给右值引用。
是某个类型&& b = foo();实际上是右值引用吗
是(阅读此处了解更多信息:Do rvalue references allow dangling references?
它是否从foo()中"窃取"了返回值,并将b中的内容发送给析构函数?
不,它延长了它的寿命
有没有其他方法可以避免这个警告?
你有三个选择:(1)赋值给右值引用,(2)赋值给常量左值引用,(3)按值返回,但在类中实现移动语义。
您还可以指望编译器会对返回值执行RVO。

相关问题