C++双向链表Link结构体remove()函数原理及内存泄漏疑问
我在学习C++,在Bjarne Stroustrup所著《The C++ Programming Language, 4th Edition》的第465、466页接触到struct Link {};相关代码。为方便理解代码执行逻辑,我在原代码基础上添加了打印内存地址的调试输出,完整代码如下(注:原代码第一行缺少#,正确写法应为#include <iostream>):
#include <iostream> using std::cout; using std::endl; struct Link { Link* prev; Link* next; int data; Link* insert(int x) { prev = new Link{prev, this, x}; cout << "address of new prev:" << prev << endl; cout << "address of new prev->prev:" << prev->prev << endl; cout << "address of new prev->next:" << prev->next << endl; cout << "prev->data :" << prev->data << endl; cout << "address of this:" << this << endl; return prev; } void remove() { cout << "\n\nRemoving elements!" << endl; if (prev) { cout << "Removing data:" << prev->data << endl; cout << "Before prev:" << prev << " " << "prev->next:" << prev->next << endl; prev->next = next; cout << "After prev:" << prev << " " << "prev->next:" << prev->next << endl; } if (next) { cout << "Removing data:" << next->data << endl; next->prev = prev; cout << "next:" << next << " " << "next->prev:" << next->prev << endl; } delete this; } void print() { Link* temp = prev; while (temp != nullptr) { cout << "temp->data:" << temp->data << endl; temp = temp->prev; } } }; int main() { Link* x {new Link}; cout << "Address of x:" << x << endl; x->prev = nullptr; x->next = nullptr; cout << "\n\nInserting:2"<< endl; x->insert(2); cout << "\n\nInserting:4"<< endl; x->insert(4); cout << "\n\nInserting:5"<< endl; x->insert(5); x->remove(); return 0; }
我在学习过程中无法准确理解remove()函数移除并销毁this指向对象的具体逻辑:根据代码实现,该函数并未遍历销毁整个链表,仅将prev->next赋值为next(当前测试场景下next值为0x0空指针),请问该理解是否正确?如果理解正确,存储数值2、4的节点所占用的内存并未被释放,这种情况是否属于内存泄漏?
你的理解完全正确,逐部分说明如下:
remove()函数的实际逻辑
这个函数的设计目标是从双向链表中摘除并释放当前this指向的单个节点,本身就不负责销毁整条链表,执行流程非常清晰:
- 若当前节点存在前驱节点(
prev不为空):将前驱节点的next指针指向当前节点的后继节点,让前驱直接跨过当前要删除的节点,和后继建立正向连接。你的测试场景里初始创建的x节点next始终是空指针,因此执行完这步后,前面插入的存5、4、2的节点链的尾端next会被设为空。 - 若当前节点存在后继节点(
next不为空):将后继节点的prev指针指向当前节点的前驱节点,补全反向连接。你的测试场景里x->next一直是空,这部分逻辑不会触发。 - 最后执行
delete this,仅释放当前this指向的这一个节点(也就是main里一开始new出来的、没有存有效业务数据的初始x节点),完全不会顺着prev/next指针遍历释放其他节点。
内存泄漏判定
你测试场景下存储2、4、5的三个节点确实没有被释放,属于典型的内存泄漏:
这三个节点都是堆上动态分配的内存,当x节点被delete之后,你没有保存任何指向这三个节点的指针,程序后续既无法访问这部分内存,也没有主动释放的路径,完全符合内存泄漏的定义——动态分配的堆内存未被释放且失去了所有访问入口,造成内存资源浪费。
需要说明的是,原书这段代码只是用来演示双向链表单节点摘除的最基础语法逻辑,并不是生产环境可用的、无内存安全问题的完整链表实现。如果要做到无泄漏,还需要补充链表整体析构时的遍历释放逻辑、节点增删时的指针所有权管理,不能直接照搬这段演示代码使用。
内容的提问来源于stack exchange,提问作者user3602207

