在可移动且不可复制的类上使用移动交换习惯是否有意义? [英] Does it make sense to use the move-and-swap idiom on a movable and non-copyable class

查看:82
本文介绍了在可移动且不可复制的类上使用移动交换习惯是否有意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有诸如此类的课程

If I have a class such as

class Foo{
public:
    Foo(){...}
    Foo(Foo && rhs){...}
    operator=(Foo rhs){ swap(*this, rhs);}
    void swap(Foo &rhs);
private:
    Foo(const Foo&);
// snip: swap code
};
void swap(Foo& lhs, Foo& rhs);

如果我没有复制构造函数,按值实现operator =并交换是否有意义?它应该防止复制我的类Foo的对象,但允许移动.

Does it make sense to implement operator= by value and swap if I don't have a copy constructor? It should prevent copying my objects of class Foo but allow moves.

此类不可复制,因此我不能复制构造或复制分配它.

This class is not copyable so I shouldn't be able to copy construct or copy assign it.

我已经用它测试了我的代码,并且似乎具有我想要的行为.

I've tested my code with this and it seems to have the behaviour I want.

#include <utility>
#include <cstdlib>
using std::swap;
using std::move;
class Foo{
public: Foo():a(rand()),b(rand()) {}
        Foo(Foo && rhs):a(rhs.a), b(rhs.b){rhs.a=rhs.b=-1;}
        Foo& operator=(Foo rhs){swap(*this,rhs);return *this;}
        friend void swap(Foo& lhs, Foo& rhs){swap(lhs.a,rhs.a);swap(lhs.b,rhs.b);}
private:
    //My compiler doesn't yet implement deleted constructor
    Foo(const Foo&);
private:
    int a, b;
};

Foo make_foo()
{
    //This is potentially much more complicated
    return Foo();
}

int main(int, char*[])
{
    Foo f1;
    Foo f2 = make_foo(); //move-construct
    f1 = make_foo(); //move-assign
    f2 = move(f1);
    Foo f3(move(f2));
    f2 = f3; // fails, can't copy-assign, this is wanted
    Foo f4(f3); // fails can't copy-construct

    return 0;
}

推荐答案

移动交换确实是合理的.如果禁用了复制构造函数,则可以使用此函数的唯一方法是使用move构造函数构造参数.这意味着如果您写

Move-and-swap is indeed reasonable. If you disable the copy constructor, then the only way that you can invoke this function is if you were to construct the argument with the move constructor. This means that if you write

lhs = rhs; // Assume rhs is an rvalue

然后,将使用move构造函数初始化operator =的参数的构造函数,清空rhs并将该参数设置为rhs的旧值.然后,调用swap交换lhs的旧值和rhs的旧值,使lhs保留rhs的旧值.最后,该参数的析构函数将触发,清理lhs的旧内存.请注意,这确实不是复制和交换,而是移动和交换.

Then the constructor of the argument to operator = will be initialized with the move constructor, emptying rhs and setting the argument to the old value of rhs. The call to swap then exchanges lhs's old value and rhs's old value, leaving lhs holding rhs's old value. Finally, the destructor for the argument fires, cleaning up lhs's old memory. As a note, this really isn't copy-and-swap as much as move-and-swap.

也就是说,您现在所拥有的是不正确的. std::swap的默认实现将在内部尝试使用move构造函数来移动元素,这将导致无限递归循环.您必须超载std::swap才能使其正常工作.

That said, what you have now isn't correct. The default implementation of std::swap will internally try to use the move constructor to move the elements around, which results in an infinite recursion loop. You'd have to overload std::swap to get this to work correctly.

您可以在线上在ideone上看到此.

有关更多信息,请参见此问题及其讨论四个半规则".

For more information, see this question and its discussion of the "rule of four-and-a-half."

希望这会有所帮助!

这篇关于在可移动且不可复制的类上使用移动交换习惯是否有意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆