RAII
資源獲得及初始化,獲得資源馬上進行初始化
是一種利用對象生命週期來控制程序資源(如內存、文件句 柄、網絡連接、互斥量等等)的簡單技術。
在對象構造時獲取資源,接着控制對資源的訪問使之在對象的生命週期內始終保持有效,最後在對象析構的時候釋放資源。藉此,我們實際上把管理一份資源的責任託管給了一個對象。
//智能指針專門用來管理動態開闢的空間
//RAII不等價於只能指針
//RAII是解決問題的思想
//智能指針是RAII思想的一種實現
template<class T>
class SmartPtr
{
public:
SmartPtr(T* ptr) //在構造函數時保存動態開闢空間的指針
:_ptr(ptr)
{
}
~SmartPtr() //在析構函數中釋放
{
delete _ptr;
}
T* get()
{
return _ptr;
}
T* operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
//託管
SmartPtr<int*> sp(new int); //這樣在外界無法訪問,需要重載 operator*() operator->()
//這樣,就算拋異常導致結束時未釋放資源,函數結束銷燬對象時會自動調用析構函數
auto_ptr
//模仿實現
template<class T>
class auto_ptr //C++98
{
public:
auto_ptr(T* ptr) //在構造函數時保存動態開闢空間的指針
:_ptr(ptr)
{
}
~auto_ptr() //在析構函數中釋放
{
delete _ptr;
}
T* operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//管理權轉移
auto_ptr(const auto_ptr<T>& ap)
:_ptr(ap._ptr) // 這樣就解決了一塊空間被多個對象使用而造成程序奔潰問題
{
ap._ptr = nullptr; //把兩個對象中的指針變爲一個
}
auto_ptr<T>& operator=(const auto_ptr<T>& ap)
{
if(this != &ap) // 檢測是否爲自己給自己賦值
{
if(_ptr) // 釋放當前對象中資源
{
delete _ptr; //放置在賦值時這個對象本身就指向空間,賦值時而忘記釋放
}
_ptr = ap._ptr; // 轉移資源到當前對象中
ap._ptr = nullptr;
}
return *this;
}
//測試函數
void test_auto_ptr()
{
auto_ptr<int> ap1(new int);
auto_ptr<int> ap2(ap1); //不定義拷貝構造則淺拷貝,釋放兩次
*ap1 = 10; //報錯 訪問空指針
ap1 = ap3;
}
private:
T* _ptr;
};
void test_auto_ptr()
{
//庫中的auto_pr
std::auto_ptr<int> ap1(new int);
std::auto_ptr<int> ap2(ap1);,//多次釋放
*ap1 = 10; //崩潰, ap1已經成爲nullptr
}
unique_ptr
//推薦使用
//簡單粗暴,不允許拷貝
//是線程安全的,訪問數據需要加鎖,不會出現同時多線程使用
template<class T>
class unique_ptr
{
public:
unique_ptr(T* ptr) //在構造函數時保存動態開闢空間的指針
:_ptr(ptr)
{
}
~unique_ptr() //在析構函數中釋放
{
delete _ptr;
}
T* operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//不允許拷貝和賦值
//// C++98防拷貝的方式:只聲明不實現+聲明成私有
// C++11防拷貝的方式:delete
unique_ptr(const unique_ptr<T>& up) = delete;
unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
//測試函數
void test_unique_ptr() //自己實現
{
std::unique_ptr<int> ap1(new int);
std::unique_ptr<int> ap2(ap1); //報錯,不能實現
}
private:
T* _ptr;
};