You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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错误,请问析构函数哪里出错了?


问题分析与修复

错误根源

  1. 析构函数迭代逻辑违规:
    你在析构函数中先释放了start指向的节点,再通过start->next获取下一个节点——此时start已经是被释放的内存,访问它的next属于未定义行为。后续迭代会基于无效内存中的随机值操作,最终触发重复释放(double free)。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 03:01:24