C++链表移动赋值和移动构造函数

Posted

技术标签:

【中文标题】C++链表移动赋值和移动构造函数【英文标题】:C++ Linked List Move Assignment and Move Constructor 【发布时间】:2021-05-31 13:40:49 【问题描述】:

我正在为我的面向对象编程课程编写一个单链表的实现。在程序中,我编写了一个名为Polynomial 的类,它实现了链表并允许我对其进行修改。链表中的节点包含两个字段:术语和指向下一个节点的指针。该术语是一个包含两个字段的结构:系数和指数。

到目前为止,我已经正确实现了该类及其方法,但是我在项目中遇到了一个需要帮助的问题。其中一个要求是我们实现了一个移动分配(?)和一个移动构造函数。不幸的是,我们的老师没有详细说明这些是什么或如何实施它们,现在我完全迷失了。我已经实现了 Copy Assignment 和 Copy Constructor,但是我不知道如何实现 Move Assignment 和 Move Constructor。

这是课程:

class Polynomial 
        Node* Head;
        int size = 0;
    public:
        Polynomial(); // default constructor
        Polynomial(const Polynomial& v); // copy constructor
        ~Polynomial();
        void addTerm(Term term);
        unsigned int degree() const;
        double coefficientFor(unsigned int exponent) const;
        void clear();

        // Copy Assignment Operator
        Polynomial& operator=(const Polynomial& rhs);

    private:
        void DeleteInvalidNode();
    ;

有什么方法可以帮助我实现这个实现以及它的目的是什么?

【问题讨论】:

【参考方案1】:

假设你想复制一个多项式从一个地方到另一个地方。例如,您可能想要编写一个方法,让我们对多项式进行某种幂运算。 (假设您已经编写了乘法运算符的重载)。这可能看起来像这样 [1]

Polynomial Polynomial::pow(int n) const

  Polynomial result = *this; // copy constructor

  for(int i = 2; i < n; i++)  result = result * *this; 

  return result; 

当您将*this 分配给第一行中的result 时,制作一个副本 很重要,否则您可能会在尝试修改*this 时对其进行修改result.

另一方面,假设您稍后使用此方法如下[2]:

Polynomial s;

// ...

s = p.pow(3); // move-assignment

p.pow(3) 的结果是一个多项式,但这里没有必要将 sp.pow(3) 保留为单独的对象,因为我们无法在后面的任何点引用称为 p.pow(3) 的对象代码。

因此,我们不需要小心在这里复制;如果有某种方法可以传输p.pow(3) 返回的对象,而无需仔细复制它的每一部分,那么我们很好。

我们这样声明这个方法:

class Polynomial

  // ...

  /** Move constructor */
  Polynomial(Polynomial &&);

  /** Move-assignment operator */
  Polynomial& operator=(Polynomial &&);

;

在这种情况下,由于您的多项式由链表表示,因此复制 Head 指针就足够了,然后对要移动的对象执行任何您需要的操作,以确保其析构函数不会t 销毁链表节点。这将取决于您如何编写所有内容,但可能您可以通过设置您已移动到 nullptr 的东西的 Head 指针等方法摆脱困境。

(当然记得在编写赋值运算符来清理 LHS 上需要清理的任何内容时!)

在您从某物移动构造或移动分配之后,您移动的对象被允许处于除了析构函数之外,它的任何功能都不能正常工作的状态;它不打算进一步使用。例如在上面s = p.pow(3) 的例子中,如果多项式有一个移动赋值运算符,那么它将被调用以将返回值移动到s,然后将在返回值上调用析构函数。


[1] 这实际上不是编写此方法的最佳方式,但它为我提供了一个快速且有些相关的示例,因此我将使用它运行。

[2] 这里有一点微妙之处,解释了为什么我把它写成两行。如果我写Polynomial s = p.pow(3) 它实际上会通过复制省略 绕过所有这些,基本上告诉Polynomial::pow 直接使用s 作为它的返回值。复制和移动分配仅在您分配给以前具有不同值的东西时才真正使用。

【讨论】:

以上是关于C++链表移动赋值和移动构造函数的主要内容,如果未能解决你的问题,请参考以下文章

c++复习笔记——右值引用(概念,使用场景),移动拷贝构造函数,赋值拷贝构造函数。

c++复习笔记——右值引用(概念,使用场景),移动拷贝构造函数,赋值拷贝构造函数。

C++5大构造函数

如何利用模板复制&移动构造函数和赋值运算符?

移动构造函数和移动赋值与拷贝构造函数和赋值构造函数的比较

C++类的默认函数