C++自定义链表实现赋值运算符报double free错误该如何解决?
问题根因分析
- 缺失自定义拷贝构造函数,触发浅拷贝
你测试代码中的Linkedlist b = a;属于拷贝初始化,调用的是拷贝构造函数而非你实现的赋值运算符。C++编译器在用户未自定义拷贝构造时会生成默认浅拷贝,直接将a的head、tail、size成员按字节复制给b,导致两个对象的head指向同一块堆内存。程序退出时b先析构释放了所有节点内存,a析构时再次释放同一块内存,直接触发double free错误。 - 赋值运算符实现存在逻辑漏洞
就算后续调用赋值运算符(比如写b = a;),现有实现也会触发异常:- 未处理自赋值场景:如果执行
a = a,开头的clear()会直接清空当前对象的所有节点,后续拷贝源已经为空,逻辑完全错误 - 尾节点处理错误:循环遍历右值链表时,每复制一个节点都会提前new下一个节点,循环结束后会多生成一个无数据的冗余节点,且没有将尾节点的
next设为NULL,也没有更新当前对象的tail和size成员,会导致链表遍历、析构逻辑异常
- 未处理自赋值场景:如果执行
修复方案
1. 实现自定义拷贝构造函数
Linkedlist::Linkedlist(const Linkedlist &l) { if (l.empty()) { head = tail = NULL; size = 0; return; } size = l.size; Node *iterRight = l.head; head = new Node; Node *iterLeft = head; while (iterRight != NULL) { iterLeft->data = iterRight->data; // 仅非最后一个节点时新建下一个节点 if (iterRight->next != NULL) { iterLeft->next = new Node; iterLeft->next->prev = iterLeft; iterLeft = iterLeft->next; } else { iterLeft->next = NULL; } iterRight = iterRight->next; } tail = iterLeft; }
2. 修复赋值运算符实现
Linkedlist &Linkedlist::operator=(const Linkedlist &l) { // 优先处理自赋值场景 if (this == &l) { return *this; } clear(); if (l.empty()) { head = tail = NULL; size = 0; return *this; } size = l.size; Node *iterRight = l.head; head = new Node; Node *iterLeft = head; while (iterRight != NULL) { iterLeft->data = iterRight->data; if (iterRight->next != NULL) { iterLeft->next = new Node; iterLeft->next->prev = iterLeft; iterLeft = iterLeft->next; } else { iterLeft->next = NULL; } iterRight = iterRight->next; } tail = iterLeft; return *this; }
3. 优化带参构造(修复原有内存泄漏问题)
原有带参构造最后会生成一个冗余节点未释放,修复后逻辑更严谨:
Linkedlist::Linkedlist(unsigned int n) { size = n; tail = NULL; if (n == 0) { head = NULL; return; } head = new Node; Node *iter = head; for(int i = 0; i < n; i++) { iter -> data = i; if (i != n-1) { iter -> next = new Node; iter -> next -> prev = iter; iter = iter -> next; } else { iter->next = NULL; } } tail = iter; }
内容的提问来源于stack exchange,提问作者Drake Ford
相关产品推荐
相关产品推荐

