如何在链表 c++ 中使用复制赋值运算符

How to use copy assignment operator with linked list c++

提问人:Mindset 提问时间:4/9/2023 更新时间:4/9/2023 访问量:107

问:

我必须使用复制构造函数和复制赋值运算符来测试链表。

list1 附加了 3 个双精度

list2 = list1,复制构造函数进入其中。

List4 = list3 = list1 是复制赋值运算符的用武之地。

然后 list4 又附加了 1 个双精度。

这是我上过的课。

// Specification file for the NumberList class
#ifndef NUMBERLIST_H
#define NUMBERLIST_H

class NumberList
{
private:
   // Declare a structure for the list
   struct ListNode
   {
      double value;           // The value in this node
      struct ListNode *next;  // To point to the next node
   }; 

   ListNode *head;            // List head pointer

public:
   // Constructor
   NumberList()
        { head = NULL; }
   
   //TO DO: Add the copy constructor 
   NumberList(const NumberList& origObject);

   //TO DO: Add the overloaded assignment operatora
   NumberList& operator=(const NumberList& objToCopy);

   // Destructor
   ~NumberList();
      
   // Linked list operations
   void appendNode(double);
   void insertNode(double);
   void displayList() const;
};
#endif

我有一个简单的复制构造函数,可以执行它必须做的事情。当我执行程序时,构造函数似乎在做必须做的事情。我假设它是因为它只使用一次复制构造函数。

NumberList::NumberList(const NumberList& origObject){
   
   cout << "copy constructor called." << endl;
   head = new ListNode;
   *head = *(origObject.head);
}

这是我拥有的复制分配运算符

NumberList& NumberList::operator=(const NumberList& objToCopy){
   cout << "overlaoded operator" << endl;
   if(this != &objToCopy){
      head = new ListNode;
      
      ListNode* nodePtr = new ListNode;
      nodePtr = objToCopy.head;
      nodePtr->next = NULL;

      ListNode* temp = objToCopy.head->next;
      while(temp){
         nodePtr->next = new ListNode;
         nodePtr->next = temp;
         nodePtr = nodePtr->next;
         nodePtr->next = NULL;

         temp = objToCopy.head->next;
      }
   }

   return *this;
}

这是在激活复制分配 list4=list3=list1 后显示的内容。

After inserting 5.5 to list4, List1 is: 
1.6

After inserting 5.5 to list4, List3 is: 
0

After inserting 5.5 to list4, List4 is: 
0
5.5

这是什么。它应该看起来像使用操作员后的样子。

After inserting 5.5 to list4, List1 is: 
1.6
4.8
7.9

After inserting 5.5 to list4, List3 is: 
1.6
4.8
7.9

After inserting 5.5 to list4, List4 is: 
1.6
4.8
5.5
7.9

我觉得我想得越多,我甚至连我写的代码都看不懂。所以我基本上一直在写东西,希望它能起作用。


C++ Linked-List Copy-构造函数 Deep-Copy

评论

0赞 Eljay 4/9/2023
我建议严格使用原始指针作为非所有权指针,并使用 a 作为所有权指针。std::unique_ptr
0赞 Some programmer dude 4/9/2023
head = new ListNode;...但是,如果当前列表不为空怎么办?带有该分配的旧列表会发生什么情况?
0赞 JaMiT 4/9/2023
“list1 has 3 doubles attaned to it” -- 在使用更长的长度进行测试之前,您可能希望使用长度为 1 的列表来验证您的代码。您确实需要测试更长的列表,但如果有任何 bug 显示在长度为 1 的列表中,则它们将更容易调试,需要跟踪的数据更少。
0赞 JaMiT 4/9/2023
“我有一个简单的复制构造函数,可以做它必须做的事情。”--好。然后,您可能可以将定义排除在最小可重现示例之外。保留声明,但省略定义(只要链接器不抱怨)。专注于出现故障的部分。保持简单。根据您的输出,您似乎只需要一个赋值即可重现该 bug。因此,您可以使用类似的东西来运行问题的示例代码。int main() { NumberList list1; NumberList list3; list1.appendNode(1.6); list1.displayList(); list3 = list1; list1.displayList(); }
0赞 Miles Budnek 4/9/2023
你的复制构造函数不会做“它必须做的事情”。它仅复制列表的第一个节点。其余的都在原件和副本之间共享。除此之外,您确实需要在问题中包含一个最小的可重现示例。当我们看不到代码时,很难告诉你你的代码出了什么问题。

答:

0赞 Some programmer dude 4/9/2023 #1

假设已经过测试并且工作正常,我建议对源列表进行简单的循环,然后只调用当前列表:appendNodeappendNode

for (auto* node = objToCopy.head; node; node = node->next)
{
    appendNode(node->value);
}

这个循环将复制整个源列表。

请记住先释放旧列表。


为了使更简单、更高效,并且在想要附加节点时不必遍历整个列表,我建议您还存储一个指向列表尾部的指针。appendNode

评论

0赞 Mindset 4/9/2023
对不起,但 vs code 警告我 auto 是一个 c++11 扩展,并且不知道如何更改它,所以我不能尝试那个循环。
1赞 Aaron Liu 4/9/2023
@Mindset 您可以安全地忽略这些类型的警告,而只是编译。如果你的环境因为某种愚蠢的原因不支持C++11,你可以用“ListNode”替换“auto”。
0赞 Some programmer dude 4/9/2023
@Mindset 这可能意味着两件事之一:要么你有一个非常旧的编译器,默认情况下不支持过去 12 年的进步;或者您使用的是使用 Clang 的 macOS 系统,由于某种原因,它仍然默认为旧的 C++03 标准。无论哪种方式,您都需要在构建时添加参数。-std=c++11