C++单链表拷贝构造函数实现遇double free错误求排查
嘿,别着急,咱们一步步拆解你遇到的问题——你看到的double free or corruption错误,其实是两个关键错误导致的,咱们逐个解决:
1. 最直接的原因:main函数里没真正调用拷贝构造函数
你写的SingleLinkedList<int> * myList2 = myList;根本不是创建新链表,只是让myList2这个指针和myList指向同一块内存里的同一个对象!就像给同一个房间装了两扇门,打开任意一扇都是同一个房间。
当你执行delete myList;时,这个链表对象已经被销毁,内存被回收了;再执行delete myList2;,就是试图去回收已经被释放的内存,这就触发了double free错误。
如果要真正创建一个独立的拷贝,你需要调用拷贝构造函数,正确的写法是:
// 用指针的方式创建拷贝 SingleLinkedList<int> * myList2 = new SingleLinkedList<int>(*myList); // 或者直接创建栈对象 SingleLinkedList<int> myList2(*myList);
2. 拷贝构造函数的实现完全错误
你的拷贝构造函数逻辑走偏了:你创建了一个局部的newList对象,把旧链表的元素插入到这个局部对象里,但完全没把newList的节点赋值给当前正在构造的对象(也就是this指针指向的对象)!
你开头写了head = nullptr; tail = nullptr;,之后就再也没修改过当前对象的head和tail——等于拷贝构造函数执行完,新对象的链表还是空的,而局部的newList在函数结束后会被销毁,它的节点也会被析构函数释放,等于完全没完成拷贝工作。
修正后的拷贝构造函数应该直接在当前对象上构建链表:
template <typename T> SingleLinkedList<T>::SingleLinkedList(const SingleLinkedList<T> &oldList) : head(nullptr), tail(nullptr) { Node *temp = oldList.head; while(temp != nullptr){ this->insert(temp->data); // 直接把元素插入到当前对象中 temp = temp->next; } }
额外提醒:遵循C++三法则
你已经声明了拷贝构造函数和析构函数,按照C++的三法则,你还需要实现拷贝赋值运算符operator=,否则如果之后用到赋值操作(比如myList2 = *myList;)会出现浅拷贝问题。这里给你一个参考实现:
template <typename T> SingleLinkedList<T>& SingleLinkedList<T>::operator=(const SingleLinkedList<T> &object) { // 先处理自赋值情况,避免自己拷贝自己 if(this == &object){ return *this; } // 先清空当前对象的所有节点 Node *temp = nullptr; while(head != nullptr){ temp = head; head = head->next; delete temp; } head = nullptr; tail = nullptr; // 再拷贝新的节点 temp = object.head; while(temp != nullptr){ this->insert(temp->data); temp = temp->next; } return *this; }
修正后的完整运行效果
当你修正以上两点后,运行代码就会输出两个独立的链表,且析构时不会再触发double free错误:
Constructor called...
Constructor called...
MyList:
10 --> 20 --> 30 -->
MyList2:
40 -->
Destructor called...
Destructor called...
内容的提问来源于stack exchange,提问作者pb.

