为什么裸指针不能随便传?std::unique_ptr 的正确用法与资源所有权管理详解

为什么 C++ 中不能随便传裹指针?

C++ 中突出的智能指针 std::unique_ptr 在实际开发中很容易得到使用,但同时也有一些系统性的误用隐患。

这篇文章打算完整理一下:

  • 为什么 把指针传给别人 时传 unique_ptr 比传裹指针更安全?

  • 你传裹指针,实际上就是在与系统的负责纠缠!


一、把指针传给别人,传裹指针不是啊!

【可行但不建议】

把裹指针传给一个函数,就像把孩子送走了但什么补给都没有一样

例如:

std::unique_ptr<MyObject> obj = std::make_unique<MyObject>();
b->Register(obj.get());  // 传的是裹指针

在这个场景中,b 存储了 obj ,如果它后续 delete 了,那么一旦 obj 重复释放,程序立即 double delete 崩毁。

【推荐】:明确表达所有权,用 unique_ptr 传递

b->Register(std::move(obj));  // 显式所有权移交

并且在 B 类里面:

void Register(std::unique_ptr<MyObject> obj) {
    obj_ = std::move(obj);
}

二、比较两种写法

【A 做事, B 接管(建议)】

// A.cpp
std::unique_ptr<MyObject> obj = std::make_unique<MyObject>();
b->Register(std::move(obj));

// B.h
void Register(std::unique_ptr<MyObject> obj);

// B.cpp
void B::Register(std::unique_ptr<MyObject> obj) {
    obj_ = std::move(obj);
}

【A 保持拥有, B 并不接管(可行】】

// B.h
void Notify(MyObject* obj);  // 不保存,也不释放

// A.cpp
b->Notify(obj.get());

三、别通传裹指针,很易的三个缺陷

Ὢ8 惊悚地一:裹指针 + delete

void B::Register(MyObject* obj) {
    obj_ = obj;
    // ...
    delete obj_;  // 很可能被 A 释放过,造成重复释放
}

Ὢ8 惊悚地二:存了, A 先释放

MyObject* obj = new MyObject();
b->Register(obj);

// ...
delete obj;  // B 里面仍然使用 obj

这种场景为黄金缺陷——指针指向的地址成了垃圾,也就是所谓的 懒缓指针 / 悬堆指针 (dangling pointer)

Ὢ8 惊悚地三:没人释放导致内存泄露

MyObject* obj = new MyObject();
b->Register(obj);  // B 没有 delete ,A 也没有

四、要抽象,就看这表

特性裹指针 (T*)std::unique_ptr<T>
是否表达所有权?❌ 否✅ 是
是否自动释放?❌ 需手动 delete✅ 自动析构释放
是否可移动?✅ 是,但无语义约束✅ 显式 move 转移所有权
易错程度⚠️ 高,易泄露/重复释放✅ 安全,编译期保障

第五、如果你真需要 "保存而不释放",怎么办?

你可以用 raw_ptr (Chromium 里用 base::raw_ptr) 或者 observer pattern

  • 无所有权关系,通知你自己已释放

  • 你自己跟踪调用者的生命周期


总结

“传裹指针有问题吗?”

回答是:把负责交给了别人,却不报告调用意图,究竟谁该 delete?

unique_ptr 則是将负责全部传达。这是环境安全编程的基础。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ปรัชญา แค้วคำมูล

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值