链表类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需要严格遵循两个原则:
- 赋值操作符通过传值参数接收对象(利用拷贝构造完成临时对象的拷贝),再调用swap交换当前对象与临时对象
- 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
相关产品推荐
相关产品推荐

