我的问题源于对std::move
inreturn
语句的深入研究,例如以下示例:
struct A
{
A() { std::cout << "Constructed " << this << std::endl; }
A(A&&) noexcept { std::cout << "Moved " << this << std::endl; }
};
A nrvo()
{
A local;
return local;
}
A no_nrvo()
{
A local;
return std::move(local);
}
int main()
{
A a1(nrvo());
A a2(no_nrvo());
}
打印 (MSVC, /std:c++17, release)
Constructed 0000000C0BD4F990
Constructed 0000000C0BD4F991
Moved 0000000C0BD4F992
我对按值返回的函数中返回语句的一般初始化规则以及在返回局部变量时适用哪些规则感兴趣,std::move
如上所示。
一般情况
关于退货声明,您可以阅读
- 计算表达式,终止当前函数,并在隐式转换为函数返回类型后将表达式的结果返回给调用者。[...]
在 cppreference.com 上。
其中复制初始化发生
- 当从一个按值返回的函数返回时
return other;
回到我的例子,根据我目前的知识 - 与上述规则相反 -A a1(nrvo());
是一个使用 prvalue直接初始化nrvo()
a1 的语句。那么,如 cppreference.com 中针对返回语句所述,哪个对象被复制初始化了呢?
std::move
案例_
对于这种情况,我参考了 ipc 关于Are returned locals automatically xvalues的回答。我想确保以下内容是正确的:std::move(local)
具有类型A&&
但no_nrvo()
被声明为返回类型A
,所以这里
将表达式的结果隐式转换为函数返回类型后返回给调用者
部分应该发挥作用。我认为这应该是左值到右值的转换:
任何非函数、非数组类型 T 的泛左值都可以隐式转换为相同类型的纯右值。[...] 对于类类型,此转换 [...] 将 glvalue 转换为 prvalue,其结果对象由 glvalue 复制初始化。
使用to convert from A&&
toA
A
的移动构造函数,这也是这里禁用 NRVO 的原因。这些规则是否适用于这种情况,我是否理解正确?此外,他们再次说由 glvalue复制初始化A a2(no_nrvo());
,但它是直接初始化。所以这也涉及到第一种情况。