C++链表析构函数触发Double free问题求助
问题描述
尝试用C++实现一个链表,链表包含指向堆上分配的node类型的指针,代码如下:
链表实现代码(linked_list.hpp)
#include <memory> template<typename T> class node { public: node(T v) : value(v) {} ~node() = default; T value; node *next; }; template<typename T, class Allocator = std::allocator<node<T>>> class linked_list { private: node<T>* head; Allocator alloc; public: linked_list() : head(nullptr) {} ~linked_list() { for (auto start = head; start != nullptr; start = start->next) { start->~node(); alloc.deallocate(start, 1); } } void push_back(T value) { node<T> *new_node = alloc.allocate(1); new (new_node) node<T>(value); if (head == nullptr) { head = new_node; return; } head->next = new_node; head = new_node; } };
main.cpp代码
#include "linked_list.hpp" int main() { linked_list<int> a; a.push_back(4); a.push_back(5); return 0; }
运行程序时出现double free detected in cache T2错误,请问析构函数哪里出错了?
问题分析与修复
错误根源
- 析构函数迭代逻辑违规:
你在析构函数中先释放了start指向的节点,再通过start->next获取下一个节点——此时start已经是被释放的内存,访问它的next属于未定义行为。后续迭代会基于无效内存中的随机值操作,最终触发重复释放(double free)。 - push_back函数逻辑错误:
你的push_back没有遍历到链表尾部,而是直接把新节点挂在当前head的next上,再将head更新为新节点。这会导致链表永远只能保留两个节点,更早的节点会丢失,同时指针混乱也会加剧析构时的内存错误。
修复方案
1. 修正push_back函数
遍历到链表真正的尾部,再挂载新节点,同时确保新节点的next初始化:
void push_back(T value) { node<T> *new_node = alloc.allocate(1); new (new_node) node<T>(value); new_node->next = nullptr; if (head == nullptr) { head = new_node; return; } // 遍历到链表最后一个节点 node<T>* current = head; while (current->next != nullptr) { current = current->next; } current->next = new_node; }
2. 修正析构函数
先保存下一个节点的指针,再释放当前节点,避免访问已释放的内存:
~linked_list() { node<T>* current = head; while (current != nullptr) { node<T>* next_node = current->next; // 提前保存下一个节点的指针 current->~node(); alloc.deallocate(current, 1); current = next_node; // 用保存的指针进行迭代 } head = nullptr; // 清空head,避免悬空指针 }
额外优化
可以在node的构造函数中直接初始化next为nullptr,省去push_back中的手动赋值:
node(T v) : value(v), next(nullptr) {}
内容的提问来源于stack exchange,提问作者Kain
相关产品推荐
相关产品推荐

