C語言中我們學過指針,那麼爲什麼在C++中還需要存在智能指針呢?
實際上它的出現就是給c++的內存管理“填坑”來的~ 因爲它的內存自己管理,所以說,有的時候使用malloc或者new創建的對象忘記釋放就會導致內存泄漏,又或者此時釋放語句之前有一段代碼是拋異常的話,那麼執行流就會亂跳,導致內存也無法釋放。
比如這一段代碼,若n太大,開闢空間失敗會拋異常,導致執行流跳出沒有釋放指針p。
void Func()
{
int n;
cin >> n;
int *p = new int;
int *t = new int[n];//失敗時拋異常
delete p;//沒有釋放p
delete t;
}
所以c++就引入了智能指針的概念來解決該問題。在瞭解智能指針之前應該先了解RAII思想。
RAII思想
智能指針的核心思想就是RAII(Resource Acquisition Is Initialization),RAII是一種利用對象生命週期來控制程序資源(如內存、文件句柄、網絡連接、互斥量等等)的簡單技術。
RAII是資源獲得即初始化,在對象構造時獲取資源,接着控制對資源的訪問使之在對象的生命週期內始終保持有效,最後在對象析構的時候釋放資源。藉此,我們實際上把管理一份資源的責任託管給了一個對象。這種做法有兩大好處:
- 不需要顯式地釋放資源。
- 採用這種方式,對象所需的資源在其生命期內始終保持有效
RAII思想就是把資源交給對象去管理,如下所示:
template<class T>
class SmartPtr
{
public:
SmartPtr(T* ptr)
:_ptr(ptr)
{}
~SmartPtr()
{
cout <<"delete :"<< _ptr << endl;
delete[] _ptr;
}
private:
T* _ptr;
};
在對象的構造階段把資源交給對象管理,對象的生命週期結束時會自動調用析構函數完成指針的釋放。如圖:拋出的異常被捕獲,同時指針也釋放了。
RAII思想--智能鎖
RAII思想可以擴展到鎖上面,因爲有時候加鎖之後未解鎖拋異常會導致執行流亂跳,而導致鎖未釋放,因此我們也可以基於此寫一個智能鎖,把這個鎖交給一個對象管理,對象出了作用域就會自動調用析構函數完成鎖的釋放。但是這裏需要注意的是,定義成員變量的時候要定義爲引用,這樣才能保證加鎖的時候是加在同一個鎖上的。
//定義成模板則若有另外類型的鎖來了也可以用這個SmartLock
template<class T>
class SmartLock
{
public:
SmartLock( T& lock)
:_lock(lock)
{}
~SmartLock()
{
cout << "unlock :" << &_lock << endl;
_lock.unlock();
}
private:
T& _lock;//使用引用,保證加鎖能加在同一個鎖上面
//引用定義成員變量,在定義它的時候初始化它
};
//使用
mutex mtx;
void add(int n, int *value)
{
SmartLock<mutex> smtlock(mtx);//用smtlock對象管理mtx這個鎖,出了作用域會自動解鎖
for (int i = 0; i < n; i++)
{
++(*value);
}
}