1. 为什么需要智能指针?
避免以下Bug:
- 内存泄露 :对象无法被释放,最常见的问题。
- 野指针 : 指针指向未知。
- 重复释放
2. 内存泄漏
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
C/C++程序中一般我们关心两种方面的内存泄漏
- 堆内存泄漏(Heap leak) :堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
- 系统资源泄漏 : 指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何避免内存泄漏
- 事前预防型。如智能指针等。
- 事后查错型。如泄漏检测工具。
3.智能指针的使用及原理
1. RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,在对象析构时释放资源。
RAII思想:根据对象的生命周期控制资源的生命周期
RAII一个应用: 智能指针 -->根据智能指针对象的生命周期控制动态开辟的资源的生命周期
template <class T>
class smartPtr
{
public:
smartPtr(T* ptr)
:_ptr(ptr)
{}
~smartPtr()
{
if (_ptr)
{
delete _ptr;
cout << "~smartPtr delete" << endl;
}
}
//管理权转移
smartPtr(smartPtr<T>& sp)
:_ptr(sp._ptr)
{
sp._ptr = nullptr;
}
smartPtr<T>& operator=(smartPtr<T>& sp)
{
if (this != &sp)
{
//释放原有资源
if (_ptr)
delete _ptr;
//管理权转移
_ptr = sp._ptr;
sp._ptr = nullptr;
}
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
2. auto_ptr
实现原理:管理权转移的思想。
void testAutoPtr()
{
//auto_ptr: 一般禁止使用, 有解引用异常的风险
auto_ptr<Date> ap(new Date);
cout << ap->_year << endl;
//拷贝时发生管理权转移
auto_ptr<Date> copy = ap; //当对象拷贝或者赋值后,前面的对象就悬空了
//发生管理权转移之后,智能指针不再拥有资源,故不能访问资源
//cout << ap->_year << endl;
cout << copy->_year << endl;
}
3. unique_ptr
设计思路:防拷贝,直接不让拷贝和赋值。
template <class T>
class uniquePtr
{
uniquePtr(T* ptr)
:_ptr(ptr)
{}
~uniquePtr()
{
if (_ptr)
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//防拷贝
uniquePtr(const uniquePtr<T>& up) = delete;
uniquePtr<T>& operator=(const uniquePtr<T>& up) = delete;
private:
T* _ptr;
};
4. shared_ptr
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
- shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
- 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
- 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
- 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
void testSharedPtr()
{
shared_ptr<Date> sp(new Date);
cout << sp->_year << endl;
cout << sp.use_count() << endl;
shared_ptr<Date> copy(sp);
cout << sp->_year << endl;
cout << sp.use_count() << endl;
shared_ptr<Date> sp2(new Date);
sp2 = sp;
cout << sp->_year << endl;
cout << sp.use_count() << endl;
}
4.C++11和boost中智能指针的关系
- C++ 98 中产生了第一个智能指针auto_ptr。
- C++ boost给出了更实用的scoped_ptr和shared_pt和weak_ptr。
- C++ TR1,引入了shared_ptr等。不过注意的是TR1并不是标准版。
- C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost的scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。