简体   繁体   English

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

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

I've been studying rvalue references (a new concept for me), and am puzzled by a warning I receive in the following class function... 我一直在研究右值参考(对我来说是一个新概念),我对以下类函数中收到的警告感到困惑......

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

This compiles successfully, but with the following warning... 这成功编译,但有以下警告......

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

I'm fully aware that I'm returning a temporary, as evidenced by the fact that I'm using an rvalue reference as my return type. 我完全知道我正在返回一个临时的,正如我使用右值引用作为我的返回类型这一事实所证明的那样。 The code seems to run fine upon execution, so why should this warrant a compiler warning? 代码似乎在执行时运行正常,那么为什么这需要编译器警告呢?

The standard answer to similar questions seems to be to copy the return value instead of using a reference, but why should I copy potentially massive amounts of temporary data when I can move it with an rvalue reference? 类似问题的标准答案似乎是复制返回值而不是使用引用,但是当我可以使用右值引用移动它时,为什么要复制潜在的大量临时数据? Isn't that why it was invented? 这不是它被发明的原因吗?

You're not moving your data. 没有移动你的数据。 You're creating a local object, creating a reference to that local object, destroying that local object, and then still using that reference. 您正在创建一个本地对象,创建对该本地对象的引用,销毁该本地对象,然后仍然使用该引用。

You should return by value, as you already found. 您应该按照您已经找到的值返回。 But instead of copying, move the data. 但不是复制,而是移动数据。 That's the safe way of ensuring you don't copy those massive amounts of data. 这是确保您不复制大量数据的安全方法。

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

Note: the std::move is technically redundant here, as ss.str() already returns an rvalue and so would already be moved. 注意: std::move在技​​术上是多余的,因为ss.str()已经返回一个rvalue,因此已经移动了。 I recommend leaving it in anyway. 无论如何,我建议把它留下。 This way works in any situation, so you don't have to think about which form to use: if you want to move, write move . 这种方式适用于任何情况,因此您不必考虑使用哪种形式:如果要移动,请写入move


As pointed out by TC, in general, though not in your case, this can prevent RVO. 正如TC所指出的那样,一般来说,虽然不是你的情况,但这可以防止RVO。 In cases where RVO is possible and where the compiler would implicitly use a move anyway, there is no need to write move explicitly. 在RVO可行的情况下以及编译器无论如何都隐式使用移动的情况下,都不需要显式地写入move For instance: 例如:

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

Here, it should already be clear to the reader that x is a local variable. 在这里,读者应该已经清楚x是局部变量。 It's normal for C++ code to return local variables without writing move , because either the compiler will elide the x local variable entirely and construct the std::string object directly in the return slot (whatever that means for your platform), or the compiler will use the move constructor of std::string implicitly anyway. C ++代码在没有编写move情况下返回局部变量是正常的,因为编译器将完全忽略x局部变量并直接在返回槽中构造std::string对象(无论对您的平台意味着什么),或者编译器将无论如何,隐式使用std::string的move构造函数。

This is analogous to returning an lvalue reference to a local variable and puts you on the fast-track to undefined behaviour. 这类似于将左值引用返回到局部变量,并使您快速跟踪未定义的行为。

Regardless of whether you return an lvalue reference or an rvalue reference, you are still referencing memory which is going to be destroyed on function exit. 无论是返回左值引用还是右值引用,您仍然引用将在函数退出时销毁的内存。

Rvalue reference return types should be reserved for cases when you are referencing an object which has a lifetime longer than the function, but you don't need it anymore, so are fine with it being moved-from for efficiency. Rvalue引用返回类型应该保留用于引用一个寿命比函数长的对象的情况,但是你不再需要它,因此为了提高效率而移动它是好的。 For example, you might have a case in which you are temporarily storing some data, but clients can choose to "steal" the data from you. 例如,您可能遇到临时存储某些数据的情况,但客户可以选择“窃取”您的数据。 Returning an rvalue reference to the data would be reasonable in that case. 在这种情况下,返回对数据的右值引用是合理的。

You return a (rvalue) reference to object (return by str() ) of temporary object ( ss ) which is destroyed at end of scope. 你返回一个(rvalue)引用的对象(由str()返回)临时对象( ss ),它在范围的末尾被销毁。

You should return object instead: 你应该返回对象:

string Sampler::Serial() const

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM