【C/C++ shared_ptr 和 unique_ptr可以互换吗?】
在 C++ 中,std::shared_ptr
和 std::unique_ptr
是两种不同的智能指针,它们有不同的所有权语义,不能直接互换,但在特定条件下可以相互转换:
1. unique_ptr
→ shared_ptr
(✅ 安全)
// unique_ptr 可以转换为 shared_ptr(移动语义)
std::unique_ptr<MyClass> unique = std::make_unique<MyClass>();
std::shared_ptr<MyClass> shared = std::move(unique); // 所有权转移// 此时 unique 变为 nullptr
assert(unique == nullptr);
2. shared_ptr
→ unique_ptr
(❌ 不安全)
std::shared_ptr<MyClass> shared = std::make_shared<MyClass>();
// 以下转换是无效的!会编译错误
std::unique_ptr<MyClass> unique = shared; // 错误:没有转换函数
3. 特殊情况:当 shared_ptr
是唯一所有者时
if (shared.use_count() == 1) {// 危险操作:手动释放所有权(不推荐)MyClass* raw = shared.get();shared.reset(); // 放弃所有权std::unique_ptr<MyClass> unique(raw); // 接管所有权
}
⚠️ 警告:这种操作非常危险,容易导致双重释放!
关键区别:
特性 | std::unique_ptr | std::shared_ptr |
---|---|---|
所有权 | 独占所有权 | 共享所有权 |
复制语义 | 不可复制(只能移动) | 可以复制 |
性能开销 | 零开销(等同原始指针) | 有引用计数开销 |
循环引用风险 | 无 | 需要配合 weak_ptr 避免 |
自定义删除器 | 支持(类型安全) | 支持(类型擦除) |
最佳实践:
-
优先使用
unique_ptr
// 默认使用 unique_ptr auto resource = std::make_unique<Resource>();// 需要共享时再转换 std::shared_ptr<Resource> shared_res = std::move(resource);
-
需要共享所有权时直接用
shared_ptr
// 明确需要共享的场景 auto shared = std::make_shared<SharedResource>();
-
避免所有权混用
同一资源不应同时被两种智能指针管理。
转换工具函数(C++17+):
// unique_ptr → shared_ptr
template<typename T>
std::shared_ptr<T> make_shared_from_unique(std::unique_ptr<T>&& unique) {return std::shared_ptr<T>(std::move(unique));
}// shared_ptr → unique_ptr (危险!仅用于特殊情况)
template<typename T>
std::unique_ptr<T> make_unique_from_shared(std::shared_ptr<T> shared) {if (shared.use_count() != 1) throw std::logic_error("Not exclusive owner!");return std::unique_ptr<T>(shared.release()); // 需要自定义删除器支持
}
结论:
unique_ptr
→shared_ptr
:✅ 安全,通过移动语义实现shared_ptr
→unique_ptr
:❌ 不安全,应避免- 设计时应明确所有权策略,避免混用
- 当需要共享所有权时,直接从源头使用
shared_ptr