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

std::unique_ptr的reset()执行顺序设计原因及相关疑问

关于std::unique_ptr::reset执行顺序的问题解答

1. 为何采用「存旧指针→替换当前托管指针→删除旧指针」的执行顺序

核心是为了规避三类未定义行为(UB):

  • 首先是标准明确提到的场景:调用删除器时可能销毁当前unique_ptr实例本身。如果执行顺序是「先删除旧指针→再替换当前托管指针」,删除操作销毁实例后,再对已销毁实例的current_ptr成员赋值属于野内存写入,直接触发UB。现有顺序把替换指针的操作放在删除之前,就算删除时实例被销毁,也不会有后续的实例成员写入操作,完全规避了该问题。
  • 其次是避免入参指针提前失效:如果传入reset的ptr和当前托管的指针指向重叠内存,或是ptr的有效性依赖当前托管对象的存续,先删除旧指针会直接导致ptr变成野指针,后续再赋值给current_ptr就会托管无效地址。
  • 最后是保证删除器执行时的实例状态正确:自定义删除器内部允许调用unique_ptr的get()等接口获取当前托管指针,现有顺序下执行删除器时,current_ptr已经被更新为新的入参指针,删除器读取到的是实例更新后的正确状态。

2. 「删除器可能销毁*this」是不是唯一原因

不是。除了这个原因外,上面提到的「避免入参指针提前失效」、「保证删除器执行时的实例状态正确」都是标准指定该执行顺序的核心考量因素。

3. 删除器调用销毁当前unique_ptr实例的场景

当自定义删除器持有当前unique_ptr实例的引用/指针,且删除器的执行逻辑包含销毁该实例的操作时,就会触发这种情况,示例代码如下:

#include <memory>
#include <iostream>

struct SelfDestructDeleter {
    std::unique_ptr<int>* self; // 持有unique_ptr实例本身的指针
    void operator()(int* p) {
        std::cout << "deleting ptr: " << p << std::endl;
        delete p;
        delete self; // 执行删除时直接销毁当前unique_ptr实例
    }
};

int main() {
    // 构造unique_ptr时把自身指针传给删除器
    auto* ptr = new std::unique_ptr<int, SelfDestructDeleter>(
        new int(42), 
        SelfDestructDeleter{ptr}
    );
    ptr->reset(); // 调用reset时会触发删除器销毁ptr指向的unique_ptr实例
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:00:01