核心区别
| 特性 | unique_ptr | shared_ptr |
|---|---|---|
| 所有权 | 独占所有权 | 共享所有权 |
| 引用计数 | 无 | 有(线程安全) |
| 拷贝 | ❌ 禁止拷贝 | ✅ 可以拷贝 |
| 移动 | ✅ 支持移动 | ✅ 支持移动 |
| 性能开销 | 极低(近乎原始指针) | 较高(引用计数开销) |
| 内存占用 | 和原始指针一样大 | 是原始指针的2倍 |
| 适用场景 | 明确单一所有权 | 多个对象共享资源 |
1. unique_ptr - 独占所有权
特点
-
一个对象只能被一个
unique_ptr拥有 -
不能拷贝,只能移动(
std::move) -
析构时自动删除对象
-
零开销(和原始指针一样高效)
使用场景
-
工厂模式返回对象
-
容器中管理对象
-
PIMPL 模式
-
任何明确只有一个所有者的情况
示例
cpp
#include <memory>
#include <iostream>
using namespace std;
class Resource {
public:
Resource() { cout << "Resource created" << endl; }
~Resource() { cout << "Resource destroyed" << endl; }
void use() { cout << "Resource used" << endl; }
};
// ✅ 正确用法
void test_unique_ptr() {
// 创建 unique_ptr
auto ptr1 = make_unique<Resource>();
ptr1->use();
// ❌ 不能拷贝
// auto ptr2 = ptr1; // 编译错误!
// ✅ 可以移动(所有权转移)
auto ptr2 = move(ptr1);
ptr2->use();
// ptr1 现在为空
// 函数结束时自动释放
}
// 工厂模式返回 unique_ptr
unique_ptr<Resource> createResource() {
return make_unique<Resource>(); // 移动语义,高效
}
// 在容器中使用
void test_container() {
vector<unique_ptr<Resource>> vec;
vec.push_back(make_unique<Resource>());
vec.push_back(make_unique<Resource>());
// 遍历(需要引用)
for (auto& ptr : vec) {
ptr->use();
}
}
2. shared_ptr - 共享所有权
特点
-
多个
shared_ptr可以共享同一个对象 -
引用计数:记录有多少个
shared_ptr指向对象 -
引用计数为 0 时自动删除对象
-
可以拷贝(引用计数增加)
-
有性能开销(维护引用计数)
使用场景
-
多个对象需要共享同一资源
-
观察者模式
-
缓存系统
-
复杂对象图
示例
cpp
#include <memory>
#include <iostream>
using namespace std;
class Resource {
public:
Resource() { cout << "Resource created" << endl; }
~Resource() { cout << "Resource destroyed" << endl; }
void use() { cout << "Resource used" << endl; }
};
void test_shared_ptr() {
// 创建 shared_ptr
auto ptr1 = make_shared<Resource>();
cout << "引用计数: " << ptr1.use_count() << endl; // 1
// ✅ 可以拷贝(引用计数增加)
auto ptr2 = ptr1;
cout << "引用计数: " << ptr1.use_count() << endl; // 2
auto ptr3 = ptr1;
cout << "引用计数: " << ptr1.use_count() << endl; // 3
ptr2->use();
ptr3->use();
// ptr2 析构,引用计数减为 2
// ptr3 析构,引用计数减为 1
// ptr1 析构,引用计数减为 0 → 删除对象
}
// 观察者模式中使用
class Subject;
class Observer {
shared_ptr<Subject> _subject; // 共享主题
};
void test_shared_ptr_container() {
vector<shared_ptr<Resource>> vec;
vec.push_back(make_shared<Resource>());
vec.push_back(make_shared<Resource>());
// 可以拷贝
auto copy = vec[0];
cout << "引用计数: " << vec[0].use_count() << endl; // 2
}
3. weak_ptr - 配合 shared_ptr 使用
特点
-
不增加引用计数
-
解决循环引用问题
-
需要
lock()获取shared_ptr -
可以检查对象是否还存在
示例
cpp
#include <memory>
#include <iostream>
using namespace std;
class Resource {
public:
Resource() { cout << "Resource created" << endl; }
~Resource() { cout << "Resource destroyed" << endl; }
void use() { cout << "Resource used" << endl; }
};
void test_weak_ptr() {
auto shared = make_shared<Resource>();
weak_ptr<Resource> weak = shared; // 不增加引用计数
cout << "引用计数: " << shared.use_count() << endl; // 1
// 使用 lock() 获取 shared_ptr
if (auto ptr = weak.lock()) {
ptr->use(); // 安全使用
}
shared.reset(); // 释放资源
// weak 已失效
if (auto ptr = weak.lock()) {
// 不会执行
} else {
cout << "资源已释放" << endl;
}
}
4. 如何选择?
决策树
text
需要共享所有权吗?
├─ 是 → 使用 shared_ptr
│ └─ 需要解决循环引用? → 使用 weak_ptr
└─ 否 → 使用 unique_ptr
└─ 需要传递所有权? → 使用 move()
具体场景
| 场景 | 推荐 | 原因 |
|---|---|---|
| 工厂模式返回对象 | unique_ptr | 明确唯一所有权 |
| 容器中的对象 | unique_ptr | 独占所有权 |
| 观察者模式 | shared_ptr + weak_ptr | 多个观察者共享主题 |
| 缓存系统 | shared_ptr | 多个消费者共享缓存 |
| 树形结构 | unique_ptr(子节点) | 父节点拥有子节点 |
| 图形对象图 | shared_ptr + weak_ptr | 避免循环引用 |
| PIMPL 模式 | unique_ptr | 唯一所有权 |
| 多线程共享 | shared_ptr | 线程安全的引用计数 |
5. 完整对比示例
cpp
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
class MyClass {
public:
MyClass(int v) : _value(v) {
cout << "MyClass(" << _value << ") created" << endl;
}
~MyClass() {
cout << "MyClass(" << _value << ") destroyed" << endl;
}
int getValue() const { return _value; }
private:
int _value;
};
// unique_ptr 示例
void unique_ptr_example() {
cout << "\n=== unique_ptr 示例 ===" << endl;
auto u1 = make_unique<MyClass>(10);
auto u2 = make_unique<MyClass>(20);
// u1->getValue(); // 10
// 移动所有权
auto u3 = move(u1);
// u1 现在为空
cout << "u3 value: " << u3->getValue() << endl; // 10
// 容器中使用
vector<unique_ptr<MyClass>> vec;
vec.push_back(move(u2));
vec.push_back(move(u3));
// vec.push_back(u2); // ❌ 编译错误,不能拷贝
cout << "vector size: " << vec.size() << endl;
}
// shared_ptr 示例
void shared_ptr_example() {
cout << "\n=== shared_ptr 示例 ===" << endl;
auto s1 = make_shared<MyClass>(100);
cout << "引用计数: " << s1.use_count() << endl; // 1
auto s2 = s1; // 共享所有权
cout << "引用计数: " << s1.use_count() << endl; // 2
auto s3 = s1;
cout << "引用计数: " << s1.use_count() << endl; // 3
// 容器中使用(可以拷贝)
vector<shared_ptr<MyClass>> vec;
vec.push_back(s1);
vec.push_back(s2);
vec.push_back(s3);
cout << "vector size: " << vec.size() << endl;
// 所有 shared_ptr 都有效
for (auto& ptr : vec) {
cout << "value: " << ptr->getValue() << ", refcount: " << ptr.use_count() << endl;
}
}
// 性能对比
void performance_comparison() {
cout << "\n=== 性能对比 ===" << endl;
cout << "sizeof(MyClass*) = " << sizeof(MyClass*) << " bytes" << endl;
cout << "sizeof(unique_ptr<MyClass>) = " << sizeof(unique_ptr<MyClass>) << " bytes" << endl;
cout << "sizeof(shared_ptr<MyClass>) = " << sizeof(shared_ptr<MyClass>) << " bytes" << endl;
}
int main() {
unique_ptr_example();
shared_ptr_example();
performance_comparison();
return 0;
}
总结
| 特性 | unique_ptr | shared_ptr |
|---|---|---|
| 用途 | 独占所有权 | 共享所有权 |
| 拷贝 | ❌ | ✅ |
| 移动 | ✅ | ✅ |
| 引用计数 | ❌ | ✅ |
| 性能 | 最快 | 较慢 |
| 内存占用 | 最小 | 较大 |
| 使用场景 | 明确单一所有者 | 多个所有者共享 |
黄金法则:
-
默认使用
unique_ptr -
只有需要共享时才用
shared_ptr -
遇到循环引用时用
weak_ptr打破

646

被折叠的 条评论
为什么被折叠?



