std::shared_ptr
和 std::unique_ptr
都是 C++ 标准库中提供的智能指针,用于管理动态分配的对象的生命周期,但它们之间有一些重要的区别。以下是两者的主要区别:
1. 所有权模型
-
std::unique_ptr
:- 独占所有权:
std::unique_ptr
表示独占所有权,即一个对象只能由一个std::unique_ptr
拥有。当std::unique_ptr
被销毁时,它所拥有的对象也会被销毁。 - 不可复制:
std::unique_ptr
不能被复制,只能被移动(move)。这意味着你不能有两个std::unique_ptr
指向同一个对象。 - 适用于单个所有者:当你确定一个对象只有一个所有者时,使用
std::unique_ptr
是最佳选择。
- 独占所有权:
-
std::shared_ptr
:- 共享所有权:
std::shared_ptr
表示共享所有权,允许多个std::shared_ptr
实例共享同一个对象的所有权。当最后一个std::shared_ptr
被销毁时,它所拥有的对象才会被销毁。 - 引用计数:
std::shared_ptr
内部维护一个引用计数,跟踪有多少个std::shared_ptr
指向同一个对象。 - 可复制:
std::shared_ptr
可以被复制。复制std::shared_ptr
会增加引用计数,销毁std::shared_ptr
会减少引用计数。 - 适用于多个所有者:当你需要多个所有者共享同一个对象时,使用
std::shared_ptr
是合适的。
- 共享所有权:
2. 性能
-
std::unique_ptr
:- 轻量级:
std::unique_ptr
没有引用计数,因此它的开销比std::shared_ptr
更小。 - 更快:由于没有引用计数,
std::unique_ptr
的性能通常更好。
- 轻量级:
-
std::shared_ptr
:- 额外开销:
std::shared_ptr
需要维护引用计数,这会带来一定的性能开销。 - 内存占用:
std::shared_ptr
需要额外的空间来存储引用计数,这可能会增加内存占用。
- 额外开销:
3. 用法
-
std::unique_ptr
:- 适用于资源独占的情况,例如文件句柄、网络连接等。
- 适用于单线程或多线程环境中的局部资源管理。
-
std::shared_ptr
:- 适用于需要多个所有者的场景,例如在多线程环境中共享资源。
- 适用于复杂的对象图,其中对象之间有相互引用的情况。
4. 自定义删除器
std::unique_ptr
和std::shared_ptr
都支持自定义删除器(deleter),允许你指定如何释放资源。这对于管理自定义分配器或需要特殊清理逻辑的资源非常有用。
5. 原子性
-
std::shared_ptr
:- 由于
std::shared_ptr
使用引用计数,它是线程安全的。引用计数的操作(如增加和减少)是原子的。 - 但是,多个
std::shared_ptr
之间的赋值和比较操作仍然是非原子的,需要适当的同步机制。
- 由于
-
std::unique_ptr
:std::unique_ptr
本身不是线程安全的,因为它不涉及引用计数。如果你需要在线程间传递std::unique_ptr
,需要使用适当的同步机制。
示例代码
cpp
深色版本
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass constructed\n"; }
~MyClass() { std::cout << "MyClass destructed\n"; }
};
void uniquePtrExample() {
std::unique_ptr<MyClass> ptr(new MyClass());
// ptr 不能被复制,只能被移动
// std::unique_ptr<MyClass> ptr2 = ptr; // 错误
std::unique_ptr<MyClass> ptr2 = std::move(ptr); // 正确
}
void sharedPtrExample() {
std::shared_ptr<MyClass> ptr(new MyClass());
// ptr 可以被复制
std::shared_ptr<MyClass> ptr2 = ptr; // 正确
std::cout << "Reference count: " << ptr.use_count() << std::endl; // 输出 2
}
int main() {
uniquePtrExample();
sharedPtrExample();
return 0;
}
总结
std::unique_ptr
适用于独占所有权的场景,性能更好,开销更小。std::shared_ptr
适用于共享所有权的场景,提供了引用计数和线程安全的引用计数操作,但会有额外的性能开销。
选择哪种智能指针取决于你的具体需求和设计。