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

时间:2015-07-03 10:41:25

标签: c++ reference rvalue

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

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();
                ^

我完全知道我正在返回一个临时的,正如我使用右值引用作为我的返回类型这一事实所证明的那样。代码似乎在执行时运行正常,那么为什么这需要编译器警告?

similar questions的标准答案似乎是复制返回值而不是使用引用,但是当我可以使用右值引用移动它时,为什么要复制潜在的大量临时数据?这不是它被发明的原因吗?

3 个答案:

答案 0 :(得分:8)

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

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

Source: local data frame [2 x 6]
Groups: id1, id2

        date ind id1 id2 code       var
1 2015-07-02   1   z  z2    2 0.7614406
2 2015-07-03   1   z  z2    2 0.5015336

注意:std::string Sampler::Serial() const { std::stringstream ss; . . [assemble a string value using data members] . return std::move(ss.str()); } 在技术上是多余的,因为std::move已经返回一个右值,因此已经移动了。无论如何,我建议把它留下。这种方式适用于任何情况,因此您不必考虑使用哪种表单:如果您想移动,请写ss.str()

正如T.C.所指出的那样,一般来说,虽然不是你的情况,但这可以防止RVO。在RVO可行的情况下以及编译器无论如何都隐式使用移动的情况下,都不需要明确地编写move。例如:

move

在这里,读者已经清楚std::string f() { std::string x; ... return x; // not std::move(x) } 是一个局部变量。 C ++代码在不编写x的情况下返回局部变量是正常的,因为编译器将完全忽略move局部变量并直接在返回槽中构造x对象(无论对您的平台意味着什么),或者编译器将隐式使用std::string的移动构造函数。

答案 1 :(得分:5)

这类似于将左值引用返回到局部变量,并使您快速跟踪未定义的行为。

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

Rvalue引用返回类型应该保留用于引用一个寿命比函数长的对象的情况,但是你不再需要它,所以为了提高效率,它可以被移动。例如,您可能遇到临时存储某些数据的情况,但客户可以选择“窃取”您的数据。在这种情况下,返回对数据的右值引用是合理的。

答案 2 :(得分:4)

您返回对作为对象(由git log返回)的(rvalue)引用,该对象在作用域末尾被销毁的临时对象(str())。

您应该返回对象:

ss