智能指针:C++内存管理的利器
目录
为什么需要智能指针?
内存泄漏的危害
智能指针的原理与使用
C++中的智能指针类型
线程安全问题
自定义删除器
C++11与Boost的关系
总结
为什么需要智能指针?
在C++中,手动管理内存一直是一个容易出错的问题。考虑以下代码:
void Func() {int* p1 = new int;int* p2 = new int;cout << div() << endl; // 可能抛出异常delete p1;delete p2;
}
如果`div()`函数抛出异常,`delete`语句将不会被执行,导致内存泄漏。这就是智能指针要解决的问题。
内存泄漏的危害
内存泄漏是指程序未能释放不再使用的内存。长期运行的程序(如操作系统、后台服务)出现内存泄漏会导致:
- 可用内存逐渐减少
- 程序响应变慢
- 最终可能导致系统崩溃
智能指针的原理与使用
智能指针基于RAII(Resource Acquisition Is Initialization)技术:
- 在对象构造时获取资源
- 在对象生命周期内保持资源有效
- 在对象析构时自动释放资源
基本实现
template<class T>
class SmartPtr {
public:SmartPtr(T* ptr = nullptr) : _ptr(ptr) {}~SmartPtr() { if(_ptr) delete _ptr; }T& operator*() { return *_ptr; }T* operator->() { return _ptr; }private:T* _ptr;
};
C++中的智能指针类型
1. auto_ptr (C++98)
auto_ptr<int> sp1(new int);
auto_ptr<int> sp2(sp1); // 管理权转移,sp1变为空
缺点:管理权转移语义不直观,已被弃用。
2. unique_ptr (C++11)
unique_ptr<int> sp1(new int);
// unique_ptr<int> sp2(sp1); // 错误:不允许拷贝
特点:
- 简单粗暴地禁止拷贝
- 轻量高效
- 可移动(使用std::move)
3. shared_ptr (C++11)
shared_ptr<int> sp1(new int);
shared_ptr<int> sp2(sp1); // 引用计数增加
原理:
- 使用引用计数管理资源
- 最后一个持有者负责释放资源
- 线程安全的引用计数操作
4. weak_ptr (C++11)
用于解决shared_ptr的循环引用问题:
struct ListNode {int _data;weak_ptr<ListNode> _prev;weak_ptr<ListNode> _next;
};
特点:
- 不增加引用计数
- 需要转换为shared_ptr才能访问资源
线程安全问题
shared_ptr的线程安全分为两方面:
1. 引用计数的操作是线程安全的(内部加锁)
2. 管理的资源本身不是线程安全的,需要额外同步
自定义删除器
对于非new创建的资源,可以指定自定义删除器:
// 释放malloc分配的内存
shared_ptr<int> sp1((int*)malloc(4), free);// 释放数组
shared_ptr<int> sp2(new int[10], [](int* p){ delete[] p; });// 关闭文件
shared_ptr<FILE> sp3(fopen("test.txt", "w"), [](FILE* p){ fclose(p); });
C++11与Boost的关系
1. C++98引入了auto_ptr(设计不佳)
2. Boost库提出了scoped_ptr、shared_ptr和weak_ptr
3. C++11借鉴Boost设计,引入了:
- unique_ptr(对应Boost的scoped_ptr)
- shared_ptr
- weak_ptr
总结
智能指针是C++现代编程中不可或缺的工具,它们:
- 自动管理内存,防止泄漏
- 提供异常安全保证
- 有明确的语义(独占或共享所有权)
- 能处理各种资源管理场景
在现代C++中,应该尽量避免使用裸指针和手动内存管理,转而使用智能指针来编写更安全、更简洁的代码。