C++ 如何实现c++;11用户定义类的移动函数?

C++ 如何实现c++;11用户定义类的移动函数?,c++,c++11,move,move-semantics,C++,C++11,Move,Move Semantics,我有一个用户定义的类(树形结构),带有实现的移动语义,还有一个swap函数。我想以正确的方式实现一个move函数,作为标准的std::move实现 在树节点类中,每个子节点都有一个指向父节点的parent指针。这意味着对于移动操作,所有子项都必须重新租用(可能有许多子项) 这意味着使用swap进行移动不是最佳选择,因为两个列表的子列表在交换后都必须重新出租。因此,我想实现一个move函数来清除moved from树 std::move实现的声明有些复杂,它们使用std::remove\u ref

我有一个用户定义的类(树形结构),带有实现的移动语义,还有一个
swap
函数。我想以正确的方式实现一个
move
函数,作为标准的std::move实现

在树节点类中,每个子节点都有一个指向父节点的
parent
指针。这意味着对于移动操作,所有子项都必须重新租用(可能有许多子项)

这意味着使用
swap
进行移动不是最佳选择,因为两个列表的子列表在交换后都必须重新出租。因此,我想实现一个
move
函数来清除moved from树


std::move实现的声明有些复杂,它们使用
std::remove\u reference::type&
返回类型。我需要这个吗?

你不需要写std::move的专业文章

如果您编写了正确的move构造函数和move赋值运算符,std::move将在您的类上工作

例如:

#include <iostream>
#include <cstring>

using namespace std;

struct Thing {
    Thing()
    : _data(new int[100])
    {
        cout << "default construct\n";

    }

    // Copy operator
    Thing(const Thing& other)
    : _data(new int[100])
    {
        cout << "copy constructor\n";
        memcpy(_data, other._data, sizeof(int) * 100);
    }

    // Move constructor
    Thing(Thing&& other) noexcept
    : _data(other._data)
    {
        cout << "move constructor\n";
        other._data = nullptr;
    }

    // assignment operator
    Thing& operator=(const Thing& rhs) {
        cout << "copy operator\n";
        if (&rhs != this) {
            Thing tmp(rhs);
            std::swap(*this, tmp);
        }
        return *this;
    }

    // move assignment operator
    Thing& operator=(Thing&& rhs) noexcept {
        cout << "move operator\n";
        std::swap(_data, rhs._data);
        return *this;
    }


    // destructor necessary since we are working in dangerous new/delete territory
    ~Thing() noexcept {
        cout << "destructor " << (_data ? "object has data" : "object is empty") << "\n";

        delete[] _data;
    }
private:
    int* _data;
};
int main()
{
    cout << "constructing a\n";
    Thing a;

    cout << "constructing b with copy of a\n";
    Thing b(a);

    cout << "moving a to newly constructed c\n";
    Thing c(std::move(a));

    cout << "moving c back to a\n";
    a = std::move(c);

    cout << "create a new d\n";
    Thing d;
    cout << "replace d with a copy of a\n";
    d = a;

    return 0;
}

编写移动语义就是编写移动构造函数/移动赋值,而不是实现移动函数。所以,您可以在move-ctor/assignment中移动另一棵树的根

class binary_tree_node {};

class binary_tree
{
public:
    binary_tree() : root(nullptr) {}

    binary_tree(binary_tree &&rhs)
        : root(rhs.root)
    {
        rhs.root = nullptr;
    }

    binary_tree& operator=(binary_tree rhs)
    {
        swap(rhs);
        return *this;
    }

    void swap(binary_tree &rhs)
    {
        std::swap(root, rhs.root);
    }

private:
    binary_tree_node *root;
};

int main()
{
    binary_tree tree1;
    binary_tree tree2 = std::move(tree1);

    return 0;
}

这是非常不清楚的。单参数
std::move
只是一个强制转换,您无需实现任何功能。而且内部
交换
通常在左值引用上运行。
删除引用
非常简单。请看,如果编译器支持
decltype(auto)
(一个C++14特性AFAIK)(请参阅大约6.5分钟后的内容),您可以稍微简化定义。我从std::move确实可以在标准容器上有效交换这一事实开始,我不希望这样。所以std::move只有在我的move-ctor/assignment进行交换时才会交换,而move-if-the-move?Makes sensestd::move只是将对象引用转换为R值引用,允许选择和对象的move构造函数或move运算符。我给你写一个小例子,好了。提供了一个例子。编译它,然后一步一步地完成。不要忘记
noexcept
。许多标准库如果不能保证移动是不可丢弃的,就会退化为更安全的复制语义。从头开始编写指针控制类的完整实现是健康的-再次强调了为什么我们不应该这样做,因为要正确无误地进行操作非常困难,而
std::unique_ptr
std::shared_ptr
则可以完美安全地使用指针完成所有您想做的事情。
class binary_tree_node {};

class binary_tree
{
public:
    binary_tree() : root(nullptr) {}

    binary_tree(binary_tree &&rhs)
        : root(rhs.root)
    {
        rhs.root = nullptr;
    }

    binary_tree& operator=(binary_tree rhs)
    {
        swap(rhs);
        return *this;
    }

    void swap(binary_tree &rhs)
    {
        std::swap(root, rhs.root);
    }

private:
    binary_tree_node *root;
};

int main()
{
    binary_tree tree1;
    binary_tree tree2 = std::move(tree1);

    return 0;
}