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

单链表析构触发double free(tcache2)及SIGABRT错误排查

单链表析构函数触发double free问题排查

我正在为课程作业实现一个仅支持头插和尾删的单链表,配合栈完成回文字符串验证。功能运行正常,但调用~List()析构函数时总会触发“double free in tcache2”错误和SIGABRT信号,调试器未提供有效信息,查阅类似问题后仍无法解决。以下是相关代码及Valgrind报错信息,恳请帮忙排查原因:

单链表内存操作相关代码

template <typename T>
List<T>::~List()
{
    Node<T> *temp = head;
    while (head != nullptr)
    {
        temp = head;
        head = head->next;
        delete temp;
    }
}
template <typename T>
void List<T>::insert_element(T data)
{
    Node<T> *newNode = new Node<T>;
    newNode->data = data;
    newNode->next = head;
    head = newNode;
}

template <typename T>
T List<T>::delete_element()
{
    T data;
    Node<T> *temp = head;
    if (head->next == nullptr)
    {
        data = head->data;
        delete head;
        head = nullptr;
        return data;
    }
    while (temp->next->next != nullptr)
    {
        temp = temp->next;
    }
    data = temp->next->data;
    delete temp->next;
    temp->next = nullptr;
    return data;
}

主程序代码

bool checkPalindrome(List<char> l, Stack<char> s, int string_len)
{
    for (size_t i = 0; i < string_len; i++)
    {
        if(l.delete_element()!=s.pop()) return false;
    }
    return true;
}

int main()
{
    List<char> characters_l;
    Stack<char> characters_s;
    string input = "kajak";
    for (size_t i = 0; i < input.length(); i++)
    {
        characters_l.insert_element(input[i]);
        characters_s.push(input[i]);

    }
    std::cout<<input<<" is "<<(checkPalindrome(characters_l, characters_s, input.length()) ? "" : "not ") <<"a palindrome"<<std::endl;

    return 0;
}

Valgrind报错信息

==21949== Invalid read of size 8
==21949==    at 0x10AA83: List<char>::~List() (list.hpp:36)
==21949==    by 0x10A727: main (lab1b.cpp:30)
==21949==  Address 0x4de0e18 is 8 bytes inside a block of size 16 free'd
==21949==    at 0x484C91D: operator delete(void*, unsigned long) (vg_replace_malloc.c:1101)
==21949==    by 0x10AAA3: List<char>::~List() (list.hpp:37)
==21949==    by 0x10A6EF: main (lab1b.cpp:27)
==21949==
==21949== Invalid free() / delete / delete[] / realloc()
==21949==    at 0x484C91D: operator delete(void*, unsigned long) (vg_replace_malloc.c:1101)
==21949==    by 0x10AAA3: List<char>::~List() (list.hpp:37)
==21949==    by 0x10A727: main (lab1b.cpp:30)
==21949==  Address 0x4de0e10 is 0 bytes inside a block of size 16 free'd
==21949==    at 0x484C91D: operator delete(void*, unsigned long) (vg_replace_malloc.c:1101)
==21949==    by 0x10AAA3: List<char>::~List() (list.hpp:37)
==21949==    by 0x10A6EF: main (lab1b.cpp:27)

问题原因

核心问题是未为List类实现拷贝构造函数和拷贝赋值运算符,违反了C++的三/五法则(自定义析构函数时,必须同时自定义拷贝构造和拷贝赋值,避免浅拷贝导致的内存问题)。

调用checkPalindrome(characters_l, ...)时,characters_l以值传递方式传入函数,触发List的默认拷贝构造函数。默认拷贝是浅拷贝,直接复制head指针,导致原对象characters_l和函数内临时对象l共享同一份链表节点内存。

函数执行完毕后,临时对象l销毁,析构函数释放所有节点内存,此时原对象characters_l的head指针变为悬空指针。main函数结束时,原对象characters_l销毁,析构函数再次尝试释放已被释放的节点,直接触发double free错误。

解决方案

方案1:改用引用传递参数

修改checkPalindrome函数的参数为引用,避免创建临时拷贝对象:

bool checkPalindrome(List<char>& l, Stack<char>& s, int string_len)

此方法简单直接,不会触发两次析构,从根源避免double free。

方案2:实现深拷贝的拷贝构造和拷贝赋值

为List类添加深拷贝逻辑,确保每个对象拥有独立的链表节点内存:

// 拷贝构造函数
template <typename T>
List<T>::List(const List<T>& other) : head(nullptr) {
    Node<T>* current = other.head;
    Node<T>* tail = nullptr;
    while (current != nullptr) {
        Node<T>* newNode = new Node<T>;
        newNode->data = current->data;
        newNode->next = nullptr;
        if (head == nullptr) {
            head = newNode;
            tail = newNode;
        } else {
            tail->next = newNode;
            tail = newNode;
        }
        current = current->next;
    }
}

// 拷贝赋值运算符(遵循copy-and-swap惯用法)
template <typename T>
List<T>& List<T>::operator=(List<T> other) {
    std::swap(head, other.head);
    return *this;
}

额外优化点

delete_element函数存在空指针风险:当链表为空时,head是nullptr,访问head->next会触发崩溃,建议添加空链表判断:

template <typename T>
T List<T>::delete_element()
{
    if (head == nullptr) {
        throw std::runtime_error("无法从空链表中删除元素");
    }
    // 原代码逻辑...
}

内容的提问来源于stack exchange,提问作者Juliusz Bednarek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:05:56