C++中new就必须delete,但可能会因为忘记写或者代码跳转忘记delete,会导致内存泄漏,因此我们需要设计一种自主的内存回收机制,让
人为的开辟内存,系统释放内存,
就不需要delete。
智能指针
普通方法开辟内存:
用智能指针开辟内存:
开辟一个堆内存交给栈上一个有名称的对象来管理,在对象里定义一个指针指向堆内存
智能指针的设计思想:
当对象的生存周期到了,系统释放这个栈上的对象,针对于这个对象销毁系统先调用析构函数,可以把堆内存当成对象的其他资源一起销毁,这样就实现了人为开辟,系统释放的自主内存回收机制。
智能指针的分类:
1、auto_ptr(C++98)
2、unique_ptr(C++11)
3、shared_ptr(C++11)
4、weak_ptr(C++11)
1、auto_ptr
temlpate<typename T>
class Auto_Ptr
{
public:
Auto_Ptr(T* ptr)
:mptr(ptr)
{}
~Auto_Ptr()
{
delete mptr;
}
T* operator->()
{
return mptr;
}
T& operator*()
{
return *mptr;
}
private:
T* mptr;
};
class Test
{
public:
void Show()
{
std::cout << "hello world!" << std::endl;
}
};
int main()
{
int* p = new int(10);
Auto_Ptr<int> pa = new int(10);
*p = 20;
*pa = 20;
Test* ptest = new Test();
ptest->Show();
Auto_Ptr<Test> apl = new Test();
apl->Show();
return 0;
}
(1)所有权唯一:旧智能指针所有权赋给新智能指针,取消掉旧智能指针的所有权
Auto_ptr<int> ap1 = new int;
Auto_ptr<int> ap2 = ap1;
针对于上述两行代码 ,它的设计是这样的:首先我们生成的是ap1这个对象,ap1这个对象中有一个指针mptr,这个mptr指向了一个堆内存。接下来通过拷贝构造生成了ap2这个对象。ap2中也有一个指针是mptr。同样ap2这个对象也指向了这个堆内存。如下图所示:
atuo_ptr会回收旧的智能指针的所有权,也就是ap2指向这个堆内存的时候,ap1就会变成旧的智能指针,同时会让ap1指向为空。保证了这个堆内存只有一个指针指向。也就是保证了这个智能指针所有权唯一的特点。如下图所示:
此时堆ap1失效了,进行解引用的时候程序会崩溃。
主要再拷贝构造函数中处理:
temlpate<typename T>
class Auto_Ptr
{
public:
Auto_Ptr(T* ptr)
:mptr(ptr)
{}
Auto_Ptr(Auto_Ptr<T>& rhs)
{
mptr = rhs.Release();//先是旧的智能指针将原来的指向的堆内存保存下来,然后将旧的智能指针置为空,然后将原来保存下来的指针赋值给新的指针。就相当于新的智能指针指向了该堆内存,同时也取消掉了旧智能指针的所有权。
}
Auto_Ptr<T>& operator=(Auto_Ptr<T>& rhs)
{
if(this != &rhs)
{
delete mptr;
mptr = rhs.Release();
}
return *this;
}
~Auto_Ptr()
{
delete mptr;
}
T* operator->()
{
return mptr;
}
T& operator*()
{
return *mptr;
}
private:
T* Release()
{
T* tmp = mptr;//首先将指针指向的堆内存保存下来
mptr = NULL;//然后将本身置成空
return tmp;//接下来将保存的地址返回出去
}
T* mptr;
};
(2)缺陷: 拷贝赋值过程中,可能导致智能指针提前失效
2、unique_ptr:
unique_ptr是借鉴scope_ptr实现的
(1)scope_ptr保证了所有权唯一,但禁止拷贝(不能用拷贝构造函数)和移动赋值(不能用赋值运算符重载函数)等操作转移权限,一个对象只能指向一个堆内存
(2)不能实现数据共享
template<typename T>
class Scope_Ptr
{
public:
Scope_Ptr(T* ptr)
:mptr(ptr)
{}
~Scope_Ptr()
{
delete mptr;
}
T* operator->()
{
return mptr;
}
T& operator*()
{
return *mptr;
}
private:
Scope_Ptr(const Unique_Ptr<T>&);//将拷贝构造函数和赋值运算符函数写在私有下
Scope_Ptr<T>& operator=(const Unique_Ptr<T>&);
T* mptr;
}
int main()
{
Scope_Ptr<int> up1(new int);
Scope_Ptr<int> up2(up1);//不允许多个智能指针指向同一个内存块
return 0;
}
3、 shared_ptr(又称为强智能指针和带引用计数的指针)
(1)允许多个智能指针对象指向同一堆内存,实现了数据共享
(2)增加引用计数:纪录该堆内存有多少个对象指向;多一个对象指向,计数器+1;少一个对象指向,计数器-1,最后一个对象销毁,释放该堆内存。
(3)shared_ptr的问题:相互引用的问题,如果在内部相互指向,会产生内存泄漏
4、weak_ptr(弱智能指针)
为了解决强智能指针相互引用的问题,是为了解决强智能指针相互引用的问题,而且他不能单独使用.
weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
(1)不能单独使用,必须结合强智能指针的使用
(2)弱智能指针不处理引用计数