智能指針主要解決被多個對象引用時,資源如何釋放的問題。
下面介紹一下boost庫中的shared_ptr和weak_ptr:
Shared_ptr:當進行拷貝和賦值操作時, shared_ptr所指向的對象的引用計數都會增加,一旦變爲0,就會自動釋放自己管理的對象。(shared_ptr所指向的對象有一個被釋放時,引用計數就會減1)
Weak_ptr: weak_ptr是一種不控制所指向對象生存週期的智能指針,它指向一個shared_ptr管理的對象時,並不會改變對象的引用計數(引用計數不增加),一旦最後一個指向shared_ptr的對象被銷燬,對象就會被釋放,即使有weak_ptr指向該對象,還是會被釋放。
當創建一個weak_ptr時,要用一個shared_ptr來初始化,由於對象可能不存在,我們不能使用weak_ptr來訪問對象,通過調用lock()方法,檢查對象是否存在,若存在,則返回一個指向共享對象的shared_ptr.
原理:在創建共享對象時,要使用強指針 shared_ptr,若將該對象給其他線程時,則需要將強指針 shared_ptr轉化爲弱指針weak_ptr
(強指針的引用計數會增加,不轉化爲弱指針則一旦被其他線程調用,則該對象將一直不能析構,weak_ptr對象引用資源不會增加引用計數)要是弱指針weak_ptr想訪問該對象時,不能通過weak_ptr來直接訪問資源,需要進行提升(shared_ptr能保證自己沒被釋放之前,所管理的資源是不會被釋放的,當shared_ptr引用計數爲0時,釋放資源,即使有weak_ptr指向它,而weak_ptr通過lock()方法來判斷所管理的資源是否被釋放,訪問時要進行提升)weak_ptr爲shared_ptr,將該弱指針提升爲強指針,若提升成功,指針不爲空,否則爲空。
重磅推薦《linux多線程服務器編程》—第一章1.6節 神器shared_ptr/weak_ptr 書目作者陳碩(很膩害的一個大神)
附上一個自己實現的智能指針,通過鏈表來存儲這些被引用的資源,當我們在實現指針的拷貝,賦值,析構等操作時,資源引用計數會相應的增加和減少。會遍歷鏈表找到該資源的類型,對該資源計數引用增加減少,若計數減少爲0時,則釋放該資源節點。
//智能指針
class HeapTable//給資源上的指針計數
{
public:
static HeapTable *Getinstance()//單例 不同類型實例化只能在同一個鏈表
{
static HeapTable mHeapTable;
return &mHeapTable;
}
~HeapTable()
{
Node *pcur=phead;
while (pcur != NULL)
{
phead=phead->mpnext;
delete pcur;
pcur=phead;
}
}
void addRef(void *ptr)
{
Node *pcur=phead->mpnext;
while (pcur != NULL)
{
if (pcur->paddr == ptr)//查找到對該資源計數器加1
{
pcur->mcount++;
return;
}
pcur=pcur->mpnext;
}
pcur=new Node;//沒查找到 進行頭插
pcur->mpnext=phead->mpnext;
phead->mpnext=pcur;
}
void delRef(void *ptr)
{
Node *pcur=phead->mpnext;
while (pcur != NULL)
{
if (pcur->paddr == ptr)//查找到對該資源計數器減1
{
pcur->mcount--;
return;
}
pcur=pcur->mpnext;
}
}
int GetRef(void *ptr)
{
Node *pcur=phead->mpnext;
while (pcur != NULL)
{
if (pcur->paddr == ptr)
{
return pcur->mcount;
}
pcur=pcur->mpnext;
}
return -1;
}
private:
HeapTable(){phead = new Node;}
class Node
{
public:Node(void *ptr=NULL):mcount(0),paddr(ptr),mpnext(NULL)
{
if (paddr != NULL)
{
mcount=1;
}
}
int mcount;
void *paddr;//指向資源
Node *mpnext;
};
Node *phead;
};
template<typename T>
class CsmartPtr
{
public:
CsmartPtr(T* str = NULL):mpstr(str)//構造
{
if (mpstr != NULL)
{
addRef();
}
}
CsmartPtr(const CsmartPtr<T> &src):mpstr(src.mpstr)//拷貝構造
{
if (mpstr != NULL)
{
addRef();
}
}
CsmartPtr<T>& operator=(const CsmartPtr<T> &src)//賦值運算符重載
{
if (this == &src)//防止自賦值
{
return *this;
}
if (mpstr != NULL)//釋放原來的空間
{
delRef();
if (GetRef() == 0)
{
delete mpstr;
mpstr=NULL;
}
}
mpstr=src.mpstr;
addRef();
return *this;
}
~CsmartPtr()
{
cout<<"this"<<this<<endl;
delRef();
if (GetRef() == 0)
{
delete mpstr;
mpstr=NULL;
}
}
T & operator *(){return *mpstr;}
const T & operator *()const{return *mpstr;}
T* operator ->(){return mpstr;}
const T * operator ->()const{return mpstr;}
void addRef(){ mpHeapTab->addRef(mpstr);}
void delRef(){ mpHeapTab->delRef(mpstr);}
int GetRef() {return mpHeapTab->GetRef(mpstr);}
private:
T *mpstr;
static HeapTable *mpHeapTab;//靜態指針
};
//靜態變量在全局進行初始化
template<typename T>
HeapTable*CsmartPtr<T>::mpHeapTab=HeapTable::Getinstance();
int main()
{
int *p = new int;
CsmartPtr<int>pointer1(new int);
CsmartPtr<int>pointer2(new int);
CsmartPtr<int>pointer3(pointer1);
pointer2=pointer1;
CsmartPtr<char> pointer4((char*)p);
return 0;
}