C++链表拷贝构造与赋值运算符实现异常问题求助
链表拷贝构造与赋值运算符问题修复
需求说明
需要测试NumberList链表的拷贝构造函数与拷贝赋值运算符:
- 给
list1添加3个double类型元素 list2 = list1调用拷贝构造函数list4 = list3 = list1调用拷贝赋值运算符- 给
list4追加一个double元素后,各链表需保持独立,修改list4不能影响list1和list3
给定类框架
// 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 operator 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); }
拷贝赋值运算符(逻辑混乱)
当前实现存在多处致命错误:
- 直接将
nodePtr指向原链表节点,导致浅拷贝,修改新链表会直接破坏原链表 - 循环逻辑错误,
temp始终指向原链表第二个节点,无法遍历完整链表 - 未释放当前对象原有节点内存,会造成内存泄漏
- 未处理原链表为空的边界情况
- 错误修改原链表节点的
next指针,破坏原链表结构
错误实现代码:
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; }
错误输出与预期输出
错误输出
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
修正后的完整实现
1. 析构函数实现(必须补充,避免内存泄漏)
NumberList::~NumberList() { ListNode* current = head; while (current != nullptr) { ListNode* next = current->next; delete current; current = next; } head = nullptr; }
2. 修正拷贝构造函数(深拷贝整个链表)
NumberList::NumberList(const NumberList& origObject) { cout << "copy constructor called." << endl; head = nullptr; // 处理原链表为空的情况 if (origObject.head == nullptr) { return; } // 拷贝头节点 head = new ListNode; head->value = origObject.head->value; head->next = nullptr; ListNode* origCurrent = origObject.head->next; ListNode* newCurrent = head; // 遍历原链表,拷贝剩余节点 while (origCurrent != nullptr) { newCurrent->next = new ListNode; newCurrent->next->value = origCurrent->value; newCurrent->next->next = nullptr; newCurrent = newCurrent->next; origCurrent = origCurrent->next; } }
3. 修正拷贝赋值运算符(深拷贝+自赋值保护+内存释放)
NumberList& NumberList::operator=(const NumberList& objToCopy) { cout << "overloaded operator called." << endl; // 自赋值保护,避免自我赋值导致的内存泄漏 if (this == &objToCopy) { return *this; } // 释放当前对象原有内存 ListNode* current = head; while (current != nullptr) { ListNode* next = current->next; delete current; current = next; } head = nullptr; // 处理被拷贝对象为空的情况 if (objToCopy.head == nullptr) { return *this; } // 深拷贝整个链表 head = new ListNode; head->value = objToCopy.head->value; head->next = nullptr; ListNode* origCurrent = objToCopy.head->next; ListNode* newCurrent = head; while (origCurrent != nullptr) { newCurrent->next = new ListNode; newCurrent->next->value = origCurrent->value; newCurrent->next->next = nullptr; newCurrent = newCurrent->next; origCurrent = origCurrent->next; } return *this; }
4. 补充appendNode实现(用于测试)
void NumberList::appendNode(double num) { ListNode* newNode = new ListNode; newNode->value = num; newNode->next = nullptr; if (head == nullptr) { head = newNode; } else { ListNode* current = head; while (current->next != nullptr) { current = current->next; } current->next = newNode; } }
5. 补充displayList实现(用于测试)
void NumberList::displayList() const { ListNode* current = head; while (current != nullptr) { cout << current->value << endl; current = current->next; } }
测试代码
#include <iostream> #include "NumberList.h" using namespace std; int main() { NumberList list1; list1.appendNode(1.6); list1.appendNode(4.8); list1.appendNode(7.9); // 调用拷贝构造函数 NumberList list2 = list1; NumberList list3, list4; // 调用拷贝赋值运算符,list3 = list1,然后list4 = list3 list4 = list3 = list1; // 给list4追加元素(若要插入到中间,可实现insertNode逻辑) list4.appendNode(5.5); // 输出各链表内容 cout << "After inserting 5.5 to list4, List1 is: " << endl; list1.displayList(); cout << endl; cout << "After inserting 5.5 to list4, List3 is: " << endl; list3.displayList(); cout << endl; cout << "After inserting 5.5 to list4, List4 is: " << endl; list4.displayList(); return 0; }
测试结果
运行后将输出符合预期的结果:
copy constructor called. overloaded operator called. overloaded operator called. 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 7.9 5.5
(注:若需要将5.5插入到4.8和7.9之间,可实现insertNode的排序插入逻辑,当前appendNode仅负责追加到链表末尾)
内容的提问来源于stack exchange,提问作者Mindset
相关产品推荐
相关产品推荐

