为什么在返回右值引用时给出 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
的移动构造函数。
我一直在研究右值引用(对我来说是一个新概念),我对在以下 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
的移动构造函数。