c++ - C ++为什么当函数签名不返回右值引用时返回右值引用会改变调用者的行为?
问题描述
我遇到了一些关于右值返回的行为,我无法理解。假设我们有以下结构:
struct Bar
{
int a;
Bar()
: a(1)
{
std::cout << "Default Constructed" << std::endl;
}
Bar(const Bar& Other)
: a(Other.a)
{
std::cout << "Copy Constructed" << std::endl;
}
Bar(Bar&& Other)
: a(Other.a)
{
std::cout << "Move Constructed" << std::endl;
}
~Bar()
{
std::cout << "Destructed" << std::endl;
}
Bar& operator=(const Bar& Other)
{
a = Other.a;
std::cout << "Copy Assigment" << std::endl;
return *this;
}
Bar& operator=(Bar&& Other) noexcept
{
a = Other.a;
std::cout << "Move Assigment" << std::endl;
return *this;
}
};
struct Foo
{
Bar myBar;
Bar GetBar()
{
return myBar;
}
// Note that we are not returning Bar&&
Bar GetBarRValue()
{
return std::move(myBar);
}
Bar&& GetBarRValueExplicit()
{
return std::move(myBar);
}
};
使用如下:
int main()
{
Foo myFoo;
// Output:
// Copy Constructed
Bar CopyConstructed(myFoo.GetBar());
// Output:
// Move Constructed
Bar MoveConstructedExplicit(myFoo.GetBarRValueExplicit());
// Output:
// Move Constructed
//
// I don't get it, GetBarRValue() has has the same return type as GetBar() in the function signature.
// How can the caller know in one case the returned value is safe to move but not in the other?
Bar MoveConstructed(myFoo.GetBarRValue());
}
现在我明白为什么Bar MoveConstructedExplicit(myFoo.GetBarRValueExplicit())
调用移动构造函数了。但是由于该函数Foo::GetBarRValue()
没有显式返回 aBar&&
我希望它的调用给出与Foo::GetBar()
. 我不明白在这种情况下为什么/如何调用移动构造函数。据我所知,没有办法知道强制转换为 rValue 引用的GetBarRValue()
实现myBar
。
我的编译器是否在对我进行优化(在 Visual Studio 的调试版本中对此进行测试,显然无法禁用返回值优化)?我觉得有点令人沮丧的是,调用方的行为可能会受到GetBarRValue()
. 签名中没有任何GetBarRValue()
内容告诉我们,如果调用两次,它将给出未定义的行为。return std::move(x)
在我看来,正因为如此,当函数没有显式返回 && 时,这是一种不好的做法。
有人可以向我解释这里发生了什么吗?谢谢!
解决方案
发生的事情是你在那里看到了省略。您正在return std::move(x)
使用简单的Bar
;类型继续构建。然后编译器正在删除副本。
GetBarRValue
您可以在此处查看未优化的程序集。对移动构造函数的调用实际上是在GetBarRValue
函数中发生的,而不是在返回时发生的。回到main
,它只是做一个简单的lea
,它根本没有调用任何构造函数。
推荐阅读
- python - 在 pyparsing 中强制标记之间的空格
- android - 我应该如何使用导航架构组件和单活动方法处理 ViewPager 片段中的导航
- algorithm - 随机森林算法的准确度为 0.0
- python - 如何使用python对文本文件中的奇数索引数求和
- ruby-on-rails - 如何格式化我的 formData 对象的结构以匹配后端的期望?
- java - 如何使用 Maven 部署多个应用引擎实例?
- c++ - C++ 二次方程未按预期出现
- regex - 我想要一个只接受由逗号或空格分隔的字符列表的正则表达式代码
- java - 最大承载能力为 500 磅的运输车辆,重量为 [130, 170, 140. 100] 的乘客名单,为了安全起见,返回 [130, 170] 以准确保留 300 磅
- windows - 目录中的文件数