智能指针 (C++)
智能指针通过RAII模式自动管理内存资源,解决了手动内存管理中的野指针、内存泄漏等问题。主要分为三种:unique_ptr实现独占所有权,只能移动不能拷贝;shared_ptr通过引用计数实现共享所有权,适用于容器和资源传递;weak_ptr辅助shared_ptr解决循环引用问题,不增加引用计数。智能指针确保资源在作用域结束时自动释放,有效提升了内存安全性和代码健壮性。
智能指针种类及其使用场景
01.指针管理的困境
-
资源释放,指针未置空
- 野指针:未初始化/指向非法地址的指针
- 指针悬空:多个指针指向同一资源
- 踩内存:多次释放
-
资源未释放:导致内存泄漏
-
资源未释放,引发
coresump
02.怎么解决?
智能指针通过RAII模式,确保资源在对象生命周期结束时自动释放,从根本上解决了手动内存管理的各种问题。
智能指针资源管理
├── 问题类型
│ ├── 资源释放,指针未置空 → unique_ptr/shared_ptr自动管理
│ ├── 野指针问题 → 智能指针初始化保证有效性
│ ├── 指针悬空 → weak_ptr解决循环引用
│ ├── 踩内存 → RAII机制防止越界
│ └── 资源未释放 → 自动析构释放资源
└── 解决方案
├── unique_ptr - 独占所有权
├── shared_ptr - 共享所有权
└── weak_ptr - 观察而不拥有
03.智能指针的种类
3.1 unique_ptr
独享所有权,辅助shared_ptr,用来解决shared_ptr循环引用,原因是弱引用不占用强引用计数没有。不能拷贝,只能移动,离开作用域自动释放内存。

class Resource
{
public:
Resource() { cout << "Resource" << endl; }
void doWork()
{ // 更直观的方法名
cout << "Resource is working" << endl;
}
~Resource() { cout << "~Resource" << endl; }
};
int main()
{
// 方式1,1:使用make_unique(推荐)C++14
std::unique_ptr<Resource> ptr0 = std::make_unique<Resource>();
ptr0->doWork();
// 方式1,2:使用new
unique_ptr<Resource> ptr1(new Resource());
ptr1->doWork();
// 方式2:演示所有权转移
unique_ptr<Resource> ptr2 = move(ptr1);
if (!ptr1)
{
cout << "ptr1 is now empty" << endl;
}
ptr2->doWork();
return 0;
}
3.2 shared_ptr
std::shared_ptr 是一种共享所有权的智能指针,多个 shared_ptr 可以指向同一个对象,资源没有明确的拥有者,通过引用计数(原子op)机制来管理对象的生命周期。当最后一个shared_ptr被销毁时,对象自动删除。通常应用在容器中管理指针/资源通过函数传递。不要使用裸指针(直接使用*声明的指针,eg:Resoure *ptr = new Resoure(); )而使用make_shared。
void containerUsage() {
cout << "\n=== 容器中使用 shared_ptr ===" << endl;
vector<shared_ptr<Resource>> resources;
// 向容器添加共享指针
resources.push_back(make_shared<Resource>("Resource1"));
resources.push_back(make_shared<Resource>("Resource2"));
resources.push_back(resources[0]); // 共享第一个资源
cout << "容器大小: " << resources.size() << endl;
cout << "Resource1 引用计数: " << resources[0].use_count() << endl;
for (const auto& resource : resources) {
resource->doWork();
}
// 清空容器
resources.clear();
cout << "容器清空后" << endl;
}
循环引用导致内存泄漏。
class BadNode {
public:
shared_ptr<BadNode> next;
shared_ptr<BadNode> prev;
string name;
BadNode(string name) : name(name) {
cout << "BadNode " << endl;
}
~BadNode() {
cout << " ~BadNode" << endl;
}
};
int() {
auto node1 = make_shared<BadNode>("Node1");
auto node2 = make_shared<BadNode>("Node2");
node1->next = node2; // node2 引用计数: 2
node2->prev = node1; // node1 引用计数: 2
cout << "Node1 引用计数: " << node1.use_count() << endl;
cout << "Node2 引用计数: " << node2.use_count() << endl;
// 离开作用域时,引用计数减为1,对象不会被销毁!
return 0;
}
那么接下来使用weak_ptr即可解决。
3.3 weak_ptr
辅助shared_ptr,用来解决shared_ptr循环引用,原因是弱引用不占用强引用计数。
class GoodNode {
public:
shared_ptr<GoodNode> next;
weak_ptr<GoodNode> prev; // 使用 weak_ptr 打破一个方向的循环
string name;
GoodNode(string name) : name(name) {
cout << "GoodNode '" << name << "' created" << endl;
}
~GoodNode() {
cout << "GoodNode '" << name << "' destroyed" << endl;
}
};
void circularReferenceSolution() {
auto node1 = make_shared<GoodNode>("Node1");
auto node2 = make_shared<GoodNode>("Node2");
node1->next = node2;
node2->prev = node1; // 使用 weak_ptr,不会增加引用计数
cout << "Node1 引用计数: " << node1.use_count() << endl; // 1
cout << "Node2 引用计数: " << node2.use_count() << endl; // 2(node1->next 持有)
// 离开作用域时,对象会被正确销毁
}
ut << "Node1 引用计数: " << node1.use_count() << endl; // 1
cout << "Node2 引用计数: " << node2.use_count() << endl; // 2(node1->next 持有)
// 离开作用域时,对象会被正确销毁
}
更多推荐

所有评论(0)