C++中返回未用malloc初始化的结构体指针为何仍有效?
问题解答
核心误解澄清
你对实例的内存分配规则和位置判断存在两处错误:
- 并非只有
malloc才会申请堆内存,C++的new操作符是和malloc作用一致的动态内存分配接口,同样会在堆上创建对象 - 代码中的
ListNode实例不是栈上分配,全部通过new分配在堆内存区域,栈帧销毁不会影响堆内存的有效性
内存分配逻辑拆解
C++中程序的内存主要分为栈、堆两大区域,二者的生命周期规则完全不同:
- 栈内存:存储函数的局部变量、参数、返回地址等,函数执行结束栈帧销毁时,该区域的所有内容都会被回收。
- 堆内存:由开发者手动通过
new/malloc申请,手动通过delete/free释放,只要不主动释放,对应的内存会在程序运行周期内一直有效。
你提供的代码中,somFunc内的每一行new操作都会执行两步动作:
- 在栈上创建一个
ListNode*类型的局部指针变量(tail、head本身是栈上的指针变量) - 在堆上创建一个
ListNode结构体实例,将实例的内存地址赋值给对应的栈上指针
// 堆上创建val=2的ListNode实例,实例地址存到栈上的tail指针 ListNode *tail = new ListNode(2); // 堆上创建val=12的ListNode实例,next成员指向第一个堆实例,实例地址存到栈上的head指针 ListNode *head = new ListNode(12, tail);
当函数返回head->next时,返回的是第一个堆上ListNode实例的地址。此时栈帧销毁只会回收tail、head这两个局部指针变量本身,堆上的两个ListNode实例完全不受影响,因此返回的指针指向的地址是有效的。
额外注意事项
这段代码存在明显的内存泄漏问题:
- 你最终只拿到了第一个堆实例的地址(存到
main的res变量),第二个堆实例(val=12的节点)的地址随着head指针被回收而丢失,永远无法被释放 - 即使后续
delete res,也只能释放第一个堆实例,第二个实例的内存会一直泄漏到程序退出
正确的写法需要保证所有new出来的实例都有对应的delete操作,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Stas Ezersky
相关产品推荐
相关产品推荐

