如何正确地从函数返回中移动对象?
Posted
技术标签:
【中文标题】如何正确地从函数返回中移动对象?【英文标题】:How to move object from a function return correctly? 【发布时间】:2020-04-24 10:50:18 【问题描述】:我有一个不应被复制而只能移动的对象,因此我试图确保函数返回对象的T&&
。我的问题是对象在返回之前就被销毁了,我不知道如何正确地做到这一点。
#include <iostream>
class Foo
public:
Foo()
a = new int;
std::cout << a << '\n';
Foo(const Foo& other) = delete;
Foo(Foo&& other)
a = other.a; other.a = nullptr;
~Foo()
std::cout << a << '\n';
delete a;
void operator= (const Foo& other) = delete;
void operator= (Foo&& other)
a = other.a;
other.a = nullptr;
int* a;
;
Foo&& createNewFoo()
return std::move(Foo());
int main()
Foo foo = createNewFoo(); // The pointer is deleted before this assigns to foo
【问题讨论】:
顺便说一句。void operator=()
看起来有点奇怪。我习惯了返回类型引用(即return *this;
)。 Canonical implementations - Assignment operator
继续 Scheff 所说的话。 void operator=()
是合法且允许的,但它是非惯用的,这增加了使用该对象的任何其他开发人员的摩擦。因为它会以令人惊讶和不寻常的方式表现。这是一个建议,不是规则以通常的方式执行,可能有充分的理由进行非典型实施。
【参考方案1】:
您正在构造一个临时对象并将其绑定到右值引用作为返回值,该临时对象将在完整表达式后立即销毁,然后返回的引用始终悬空。
将函数更改为按值返回就可以了;右值将被移动到返回值。
Foo createNewFoo()
return Foo();
顺便说一句:对于上面的代码,Foo foo = createNewFoo();
不会复制/移动任何东西,因为copy elision,这是从 C++17 开始保证的。
编辑
那么为什么在返回
return Foo();
时临时不立即销毁
按值返回,返回顺序为
-
临时搭建
从临时移动构造返回值
临时被销毁
对于按引用返回,顺序是
-
临时搭建
将临时值绑定到返回值
临时被销毁
返回值(引用)变得悬空
【讨论】:
那么为什么在返回时临时没有立即销毁 return Foo();引用是否在分配之前被销毁,而返回对象本身意味着在之后销毁它? 我明白了。当您在这些步骤中说“返回值”时,您的意思是在将函数分配给 foo 之前从函数创建的临时值 Foo foo = createNewFoo();对?所以本质上,假设没有优化,按值返回,有一个从本地临时到返回值的移动,然后在 Foo foo = createNewFoo(); ? @Zebrafish 是的,有 2 个动作(在 C++17 之前的概念中)。 (事实上两者都被省略了。)【参考方案2】:您只需执行以下操作:
static Foo createNewFoo()
return Foo();
由于Foo()
已经是一个右值,因此不需要std::move
。
【讨论】:
Foo() 不是右值引用!它根本不是参考。 @IgorR。对不起,我想快点写错了。答案已更新以上是关于如何正确地从函数返回中移动对象?的主要内容,如果未能解决你的问题,请参考以下文章