智能指針:
在C++中使用堆內存是非常頻繁的操作,堆內存的申請和釋放都由程序員自己管理。使用普通指針,容易造成堆內存泄露,二次釋放等問題,使用智能指針能更好的管理堆內存。C++11中引入了智能指針的概念,方便管理堆內存。
棧、堆區別
棧:系統開闢 系統釋放
堆:手動開闢 手動釋放
設計:手動開闢 系統釋放
圖示:
手動開闢堆內存,利用對象生存週期結束後會調用析構,讓對象來管理這個堆內存,從而達到 手動開闢,系統析構的目的。
最初始的智能指針:管理權唯一
如果有多個智能指針指向同一個堆內存,會在拷貝構造或賦值過程中讓其他的智能指針失效(置空)
#include<iostream>
using namespace std;
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* ptr=NULL):mptr(ptr){}
SmartPtr(const SmartPtr& rhs):mptr(rhs.mptr)//讓兩個智能指針指向同一個堆內存
{
rhs.Release();
}
SmartPtr<T> operator=(const SmartPtr<T>& rhs)
{
if (this != &rhs)
{
delete mptr;//要麼有唯一智能指針指向堆內存,要麼指向空
mptr = rhs.mptr;
rhs.Release();
}
return *this;
}
~SmartPtr()
{
delete mptr;
mptr = NULL;
}
private:
void Release()const//舊的智能指針置爲空
{
(T*)mptr = NULL;
}
private:
T* mptr;
};
int main()
{
int *p=new int;//堆內存
SmartPtr<int> sp1(p);
SmartPtr<int> sp2(sp1);
sp1=sp2;
return 0;
}
調試結果:
可以看出,當生成sp2時,sp1指向爲空,指向的內存正是p所指向的堆內存。
可以看出,sp1=sp2;執行後,內存的管理權在sp1手上。
普通指針有指向和解引用的使用方法,同理智能指針也具有,需要運算符的重載。
#include<iostream>
using namespace std;
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* ptr = NULL) :mptr(ptr) {}
SmartPtr(const SmartPtr& rhs) :mptr(rhs.mptr)//讓兩個智能指針指向同一個堆內存
{
rhs.Release();
}
SmartPtr<T>& operator=(const SmartPtr<T>& rhs)
{
if (this != &rhs)
{
delete mptr;//要麼有唯一智能指針指向堆內存,要麼指向空
mptr = rhs.mptr;
rhs.Release();
}
return *this;
}
T& operator*()//解引用運算符的重載
{
return *mptr;
}
T* operator->()//指向運算符的重載
{
return mptr;
}
~SmartPtr()
{
delete mptr;
mptr = NULL;
}
private:
void Release()const//舊的智能指針置爲空
{
(T*)mptr = NULL;
}
private:
T* mptr;
};
class Test
{
public:
Test(int a):ma(a){}
void Show()
{
cout << ma << endl;
}
private:
int ma;
};
int main()
{
int *p=new int;//堆內存
SmartPtr<int> sp1(p);
SmartPtr<int> sp2(sp1);
sp1 = sp2;
//普通指針的用法
Test *ptest = new Test(30);//成員變量是 Test *mptr;
ptest->Show();
//智能指針的用法
SmartPtr<Test> sp3(ptest);
sp3->Show();
(*sp3.operator->()).Show();
return 0;
}
解釋:(*sp3.operator->()).Show();//(sp3.operator->())->Show();
sp3.operator->()返回一個 T* 指針,*T解引用,即對象,對象調用方法,合情合理。