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

链表类swap与赋值操作符自调用引发栈溢出问题排查

栈溢出异常排查与修复(LinkedList的copy-and-swap无限递归问题)

问题描述

  • 在Visual Studio中打印ArrayList元素时触发栈溢出,报错:Unhandled exception at 0x00007FF9E8AF8739 (ucrtbased.dll) in List.exe: 0xC00000FD: Stack overflow
  • 需求场景:读取数字文件,将每个数字的数位存入LinkedList,再把链表加入ArrayList并打印,两类均重载了operator<<
  • 已定位问题:LinkedList类的swap函数与赋值操作符互相调用,引发无限递归耗尽栈空间

问题根源

copy-and-swap idiom的核心逻辑是赋值操作符调用swap交换资源,但如果实现时出现循环调用(比如swap里调用赋值操作符,或者赋值操作符内部错误调用自身),就会触发无限递归,最终导致栈溢出。

修复方案

正确实现LinkedList的copy-and-swap需要严格遵循两个原则:

  1. 赋值操作符通过传值参数接收对象(利用拷贝构造完成临时对象的拷贝),再调用swap交换当前对象与临时对象
  2. swap函数仅负责交换对象的内部成员,绝对不能调用赋值操作符

修复后的LinkedList核心代码

class LinkedList {
    // 假设内部成员为:节点指针head、tail,以及链表长度size
    Node* head = nullptr;
    Node* tail = nullptr;
    size_t size = 0;
public:
    // 拷贝构造函数:实现深拷贝逻辑
    LinkedList(const LinkedList& other) {
        // 遍历other的节点,逐一复制到当前链表
        Node* curr = other.head;
        while (curr) {
            // 调用add节点的方法添加到当前链表
            add(curr->data);
            curr = curr->next;
        }
    }

    // 赋值操作符:传值参数+swap
    LinkedList& operator=(LinkedList other) {
        swap(*this, other);
        return *this;
    }

    // swap函数:仅交换内部成员,无赋值操作
    friend void swap(LinkedList& first, LinkedList& second) noexcept {
        using std::swap;
        // 交换所有核心成员
        swap(first.head, second.head);
        swap(first.tail, second.tail);
        swap(first.size, second.size);
    }

    // 其他成员函数(如add节点、重载operator<<等)...
};

关键注意点

  • 赋值操作符用值传递参数:这样会自动调用拷贝构造函数生成临时对象,避免手动拷贝的繁琐和错误
  • swap函数标记noexcept:保证异常安全,标准库的swap也会优先选择noexcept的重载
  • 拷贝构造必须是深拷贝:避免浅拷贝导致的重复释放内存问题

验证方式

修复后重新编译运行,打印ArrayList元素时不再触发栈溢出,同时确认文件读取、链表存储、打印功能均正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:17:12