假设我们有一个名为AAA
支持两者复制/移动:
class AAA
{
public:
AAA() = default;
~AAA() = default;
AAA(const AAA& rhs)
{
std::cout << "Copy constructor" << std::endl;
}
AAA(AAA&& rhs)
{
std::cout << "Move constructor" << std::endl;
}
};
在下面的代码中,get_val
回报second
:
AAA get_val()
{
auto [ first, second ] = std::make_tuple(AAA{}, AAA{});
std::cout << "Returning - " << std::endl;
return second;
}
auto obj = get_val();
std::cout << "Returned - " << std::endl;
Now second
被复制,打印以下输出:
...
Returning -
Copy constructor
Returned -
这是不幸的,因为我对结果的期望是要么没有调用复制构造函数,要么至少是隐含地 moved.
为了避免复制,我必须明确应用std::move
on it.
return std::move(second);
然后我会收到以下结果:
...
Returning -
Move constructor
Returned -
我认为原因是RVO没有执行是编译器可能会看到second
作为参考,同时get_val
返回纯右值。
然而,为什么隐性移动也不能被预期呢?
使用显式std::move
在这种特殊情况下, return 语句看起来并不直观,因为你通常不希望 RVO 意外消失,在大多数情况下,RVO 是比 move 更好的优化 https://stackoverflow.com/questions/19267408/why-does-stdmove-prevent-rvo.
由编译器 gcc 和 clang 进行测试-O3
.
现场演示 https://wandbox.org/permlink/5RPFJstLvYo62ThB