一、 原理 :RAII 資源獲取即初始化技術
原理:接受一個申請好的內存地址,構造一個保存在棧上的智能指針對象,當程序退出棧的作用域範圍後,由於棧上的變量自動被銷燬,智能指針內部保存的內存也就被釋放掉了(除非將智能指針保存起來)。
爲什麼這麼6呢?
在傳統 C++ 中,『記得』手動釋放資源,總不是最佳實踐。因爲我們很有可能就忘記了去釋放資源而導致泄露。所以通常的做法是對於一個對象而言,我們在構造函數的時候申請空間,而在析構函數(在離開作用域時調用)的時候釋放空間,也就是我們常說的 RAII 資源獲取即初始化技術。
#include <iostream>
#include <memory>
using namespace std;
class CData
{
public:
CData(int iSize) :m_iSize(iSize)
{
}
public:
int m_iSize;
static CData* m_CDataModule;
};
CData* CData::m_CDataModule = new CData(19);
bool PtrIsNull()
{
if(NULL == CData::m_CDataModule)
{
return false;
}
return true;
}
void TestFunc()
{
bool bResult = PtrIsNull();
cout <<"01 CData::m_CDataModule->m_iSize " << CData::m_CDataModule->m_iSize << endl;
shared_ptr<CData> shPtrA(CData::m_CDataModule);
}
int main()
{
TestFunc();
bool bResult = PtrIsNull();
cout << "02 CData::m_CDataModule->m_iSize " << CData::m_CDataModule->m_iSize << endl;
int iCount = 0;
cin.get();
return 0;
}
這是在使用智能指針之前
01 CData::m_CDataModule->m_iSize 19
02 CData::m_CDataModule->m_iSize 19
使用智能指針之後,程序第二次輸入雜亂無章的數值,是因爲堆空間被釋放掉了
01 CData::m_CDataModule->m_iSize 19
02 CData::m_CDataModule->m_iSize -572662307
注意PtrIsNull()返回的是 true,這是因爲智能指針對堆空間進行了釋放,但是對原來的指針沒有進行操作
二、引用計數
引用計數是這樣一個技巧,記錄同一個實例被引用的次數,當引用次數大於0時可用,等於0時釋放內存。引用計數的使用常有兩個目的:
- 簡化跟蹤堆中(也即C++中new出來的)的對象的過程。一旦一個對象通過調用new被分配出來,記錄誰擁有這個對象是很重要的,因爲其所有者要負責對它進行delete。但是對象所有者可以有多個,且所有權能夠被傳遞,這就使得內存跟蹤變得困難。引用計數可以跟蹤對象所有權,並能夠自動銷燬對象。可以說引用計數是個簡單的垃圾回收體系。這也是本文的討論重點。
- 節省內存,提高程序運行效率。如何很多對象有相同的值,爲這多個相同的值存儲多個副本是很浪費空間的,所以最好做法是讓左右對象都共享同一個值的實現。C++標準庫中string類採取一種稱爲”寫時複製“的技術,使得只有當字符串被修改的時候才創建各自的拷貝,否則可能(標準庫允許使用但沒強制要求)採用引用計數技術來管理共享對象的多個對象。
#include <iostream>
#include <memory>
using namespace std;
class CData
{
public:
CData(int iSize) :m_iSize(iSize)
{
}
public:
int m_iSize;
static CData* m_CDataModule;
};
CData* CData::m_CDataModule = new CData(19);
int main()
{
shared_ptr<CData> shaPtrCDataA(CData::m_CDataModule);
shared_ptr<CData> shaPtrCDataB = shaPtrCDataA;
cout << "Now Use Count"<< shaPtrCDataB.use_count() << endl;
shared_ptr<CData> shaPtrCDataC= shaPtrCDataB;
cout << "Now Use Count" << shaPtrCDataB.use_count() << endl;
shaPtrCDataA.reset();
cout << "Now Use Count" << shaPtrCDataB.use_count() << endl;
cin.get();
return 0;
}
輸出如下:
Now Use Count2
Now Use Count3
Now Use Count2
在這裏reset執行一次,引用次數就少一次