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

自定义实现UniquePtr出现double free双重释放错误的原因

问题根因

核心bug出在自行实现的UniquePtr移动构造函数没有对当前新对象的t_成员做初始化,直接对未定义的野指针执行swap操作,违反了独占指针的所有权独占语义,最终触发双重释放错误。

具体逻辑说明

  • C++类的非静态成员变量如果不在构造函数初始化列表显式赋值,默认就是未初始化的野值,指向随机内存地址,没有确定值。
  • 存在问题的移动构造实现如下:
UniquePtr(UniquePtr&& oth) {
    std::swap(t_, oth.t_);
}

执行swap时,当前正在构造的新对象的t_是随机野指针,交换后被移动的源对象oth会持有这个野指针,而非标准要求的nullptr。

  • 当源对象oth(比如lambda内的局部指针、移动构造产生的临时对象)离开作用域析构时,会对这个野指针执行delete:如果野指针刚好指向之前已经释放过的堆内存,就会触发double free;如果指向其他非法内存地址,也会触发内存访问错误。本次运行时栈内存残留值刚好出现了0(空指针,delete空指针本身是无操作)和已释放的Obj对象地址,因此打印delete 0后触发双重释放报错。
  • 前两个测试块未触发问题的原因:第一个块仅涉及直接构造和析构,没有调用移动构造;第二个块在C++17及以上标准中会触发强制拷贝消除,临时对象直接构造在目标对象的内存空间,不会调用移动构造,因此没有踩中bug。

修复方案

修改移动构造函数,在初始化列表先将当前对象的t_置为nullptr再执行交换,保证交换后源对象持有的是空指针,析构时不会释放非法内存:

UniquePtr(UniquePtr&& oth) : t_(nullptr) {
    std::swap(t_, oth.t_);
}

也可以用更直观的所有权转移写法,直接接管源对象的指针后将源对象指针置空:

UniquePtr(UniquePtr&& oth) : t_(oth.t_) {
    oth.t_ = nullptr;
}

补充:当前实现的移动赋值运算符逻辑也不严谨,建议增加自移动判断、提前释放当前对象持有的堆内存后再转移所有权,避免出现内存泄漏或重复释放问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:21:51