为什么在返回右值引用时给出 C++ 编译器警告?

Why give a C++ compiler warning when returning an rvalue reference?

我一直在研究右值引用(对我来说是一个新概念),我对在以下 class 函数中收到的警告感到困惑...

string&& Sampler::Serial() const {
    stringstream ss;
    .
    . [assemble a string value using data members]
    .
    return ss.str();
}

编译成功,但出现以下警告...

..\Metrics\Sampler.cpp:71:16: warning: returning reference to temporary [-Wreturn-local-addr]
  return ss.str();
                ^

我完全知道我是 return 临时的,我使用右值引用作为我的 return 类型这一事实证明了这一点。代码在执行时似乎 运行 没问题,那么为什么这会导致编译器警告?

similar questions 的标准答案似乎是复制 return 值而不是使用引用,但是当我可以使用右值参考?这不就是发明它的原因吗?

你 return 对临时对象 (ss) 的对象 (return by str()) 的(右值)引用,它在作用域结束时被销毁。

您应该 return 反对:

string Sampler::Serial() const

这类似于 return对局部变量的左值引用,使您快速进入未定义行为。

无论您 return 是左值引用还是右值引用,您仍然引用将在函数退出时销毁的内存。

Rvalue 引用 return 类型应该保留用于引用生命周期比函数长的对象的情况,但您不再需要它,所以可以移动它 -从效率。例如,您可能有这样一种情况,您正在临时存储一些数据,但客户可以选择 "steal" 来自您的数据。在这种情况下,返回对数据的右值引用是合理的。

没有移动您的数据。您正在创建一个本地对象,创建对该本地对象的引用,销毁该本地对象,然后仍然使用该引用。

您应该 return 按值,正如您已经找到的那样。但不是复制,而是移动数据。这是确保您不会复制大量数据的安全方法。

std::string Sampler::Serial() const {
    std::stringstream ss;
    .
    . [assemble a string value using data members]
    .
    return std::move(ss.str());
}

注意:std::move 在这里在技术上是多余的,因为 ss.str() 已经 return 是一个右值,因此已经被移动了。无论如何,我建议保留它。这种方式在任何情况下都有效,因此您不必考虑使用哪种形式:如果要移动,请写 move.


正如T.C所指出的那样,一般来说,尽管不是你的情况,这可以防止RVO。如果 RVO 是可能的,并且编译器无论如何都会隐式使用移动,则无需显式编写 move。例如:

std::string f() {
  std::string x;
  ...
  return x; // not std::move(x)
}

到这里,reader应该已经很清楚了,x是一个局部变量。 C++ 代码 return 局部变量不写 move 是正常的,因为要么编译器会完全省略 x 局部变量并直接在 [=] 中构造 std::string 对象36=] 插槽(无论这对您的平台意味着什么),否则编译器将隐式地使用 std::string 的移动构造函数。