SinglyLinkedList单链表删除节点时内存泄漏原因排查
内存泄漏根因定位
泄漏点完全出在addToTail方法的实现逻辑上,和你观察到的「链表节点数超过1个才触发泄漏」的现象完全匹配。
先看问题代码:
template <class E> SinglyLinkedNode<E>* SinglyLinkedList<E>::addToTail(E data) { SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data); if (size == 0) { head = singlyLinkedNode; tail = singlyLinkedNode; size++; return singlyLinkedNode; } // 问题出在这两行 tail->nextNode = new SinglyLinkedNode<E>(data); tail = tail->nextNode; size++; return singlyLinkedNode; }
当链表非空(即已有至少1个节点,执行第2次及以后的add操作)时,函数一上来就通过new创建了一个新节点存在singlyLinkedNode指针里,但走非空分支时完全没有使用这个已经申请内存的节点,反而再次new了一个新节点挂到尾节点后面。最后返回的还是最开始创建的、根本没有被链接到链表结构里的孤立节点。
这就导致每往非空链表加一个节点,就会泄漏一块SinglyLinkedNode大小的内存:这个孤立节点既不在链表的遍历路径上,也没有被主动释放,等链表出作用域调用析构函数执行clear()时,只会释放顺着head/tail指针能遍历到的节点,泄漏的节点永远不会被回收。你的测试用例每次循环创建链表加3个节点,第一次add(首节点)无泄漏,第二次、第三次add各泄漏1个节点,无限循环下内存会持续上涨。
修复方案
直接修改addToTail的非空分支逻辑,复用一开始创建好的节点,不要重复申请内存即可:
template <class E> SinglyLinkedNode<E>* SinglyLinkedList<E>::addToTail(E data) { SinglyLinkedNode<E>* singlyLinkedNode = new SinglyLinkedNode<E>(data); if (size == 0) { head = singlyLinkedNode; tail = singlyLinkedNode; size++; return singlyLinkedNode; } tail->nextNode = singlyLinkedNode; tail = singlyLinkedNode; size++; return singlyLinkedNode; }
其他潜在问题
这些问题不是本次内存泄漏的直接原因,但运行时会触发逻辑错误或未定义行为,建议一并修复:
contains(SinglyLinkedNode<E>* singlyLinkedNode)方法中,遍历用的currentNode指针类型写错为SinglyLinkedList<E>*,且循环内没有移动指针的逻辑,会触发编译错误或死循环,应将类型改为SinglyLinkedNode<E>*,循环内补充currentNode = currentNode->nextNode;的遍历逻辑。isEmpty()方法没有编写size不为0时的返回分支,非空状态下调用会返回未定义值,补充return false;即可。- 拷贝赋值运算符
operator=参数为值传递,会触发不必要的链表拷贝,且没有处理自赋值场景、没有清空链表原有数据,建议改为const引用传参,执行拷贝逻辑前先调用clear()释放原有节点内存。 SinglyLinkedNode的析构函数中将nextNode置空属于冗余逻辑,节点被释放后其成员指针已无意义,该操作不影响功能但没有实际必要。
内容的提问来源于stack exchange,提问作者Christopher Barrios Agosto
相关产品推荐
相关产品推荐

