您好,登錄后才能下訂單哦!
shared_ptr雖然方便,但是它有著一個致命的缺陷就是循環引用問題,因為shared_ptr本身并沒有能力解決這個問題,所以我們又引入了弱指針weak_ptr來輔助shared_ptr解決這個問題。
那么循環引用又是什么場景?
舉個栗子:
假設現在我們要創建一個雙向×××鏈表,但是這個鏈表的指針域全部都用shared_ptr維護:
struct Node
{
int _data;
shared_ptr<Node> _next;
shared_ptr<Node> _prev;
}
假設現在先創建兩個結點,并用shared_ptr維護這兩個結點:
shared_ptr<Node> sp1(new Node);
shared_ptr<Node> sp2(new Node);
現在將這兩個指針互相連接:
sp1->_next=sp2;
sp2->prev=sp1;
為了解決循化引用問題,我們又引入了weak_ptr弱指針,用來輔助shared_ptr。注意weak_ptr不能單獨使用,必須輔助shared_ptr才能使用。weak_ptr是一種不控制所指向對象生存周期的智能指針,它指向一個由shared_ptr管理的對象,將一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數。一但最后一個指向對象的shared_ptr被銷毀,對象就會被銷毀,即使有weak_ptr指向對象,對象還是會被釋放。
例:
所以為了解決上面栗子中的循環引用問題,我們可以將指針域的智能指針聲明為弱指針。
struct Node
{
int _data;
weak_ptr<Node> _next;
weak_ptr<Node> _prev;
}
二、定置刪除器
一般情況下,我們都用智能指針是用來管理動態內存的,其實智能指針是用來管理資源的,資源很多,動態內存只是資源的一種,比如說我們可以用智能指針來管理文件,那么我們就不能用智能指針默認的刪除器了,因為要管理文件的話最后是fclose,而不是delete,所以我們就必須自己定制一個刪除器。
例:以管理文件為例,實現定置刪除器。
要實現定置刪除器,就要用到仿函數:仿函數就是將"()"重載。
//定置刪除器的仿函數 struct Fclose { void operator()(void *ptr) { fclose((FILE *)ptr); cout << "fclose()" << endl; } }; void test() { boost::shared_ptr<FILE> sp(fopen("test.txt","w"),Fclose()); //調用構造函數構造一個匿名對象傳遞過去,文件正常關閉 } 再舉一個栗子: 用智能指針管理malloc開辟的動態內存,那么我們在釋放的時候就要用free釋放: //定置刪除器的仿函數 struct Free { void operator()(void *ptr) { free(ptr); } }; void test() { boost::shared_ptr<int> sp((int *)malloc(sizeof(int)),Free()); //能夠正確的釋放空間 }
三、簡單的實現一個有定置刪除器的shared_ptr
struct Fclose { void operator()(void *ptr) { fclose((FILE *)ptr); cout << "fclose()" << endl; } }; struct Free { void operator()(void *ptr) { free(ptr); cout << "free()" <<endl; } }; //默認刪除器是delete struct DefaultDel { void operator()(void* ptr) { delete ptr; cout << "delete ptr" << endl; } }; template<typename T, typename D = DefaultDel> class SharedPtr //采用引用計數,實現一個可以有多個指針指向同一塊內存的類模板,SharedPtr是類模板,不是智能指針類型 { public: SharedPtr(T* ptr, D del = DefaultDel()); SharedPtr(const SharedPtr<T,D>& sp); SharedPtr<T,D>& operator=(SharedPtr<T,D> sp); T& operator*(); T* operator->(); ~SharedPtr(); int Count() { return *_pCount; } private: void Release() { if (--(*_pCount) == 0) { _del(_ptr); delete _pCount; _ptr = NULL; _pCount = NULL; } } private: T* _ptr; int* _pCount; D _del; }; template<typename T, typename D = DefaultDel> SharedPtr<T,D>::SharedPtr(T* ptr,D del) :_ptr(ptr) , _pCount(new int(1)) ,_del(del){} template<typename T, typename D = DefaultDel> SharedPtr<T,D>::SharedPtr(const SharedPtr<T,D>& sp) { _ptr = sp._ptr; _pCount= sp._pCount; ++(*_pCount); } template<typename T, typename D = DefaultDel> SharedPtr<T,D>& SharedPtr<T,D>::operator=(SharedPtr<T,D> sp) { std::swap(sp._ptr,_ptr); std::swap(sp._pCount,_pCount); return *this; } template<typename T, typename D = DefaultDel> T& SharedPtr<T,D>::operator*() { return *_ptr; } template<typename T, typename D = DefaultDel> T* SharedPtr<T,D>::operator->() { return _ptr; } template<typename T, typename D = DefaultDel> SharedPtr<T,D>::~SharedPtr() { Release(); } //測試用例 void test() { SharedPtr<int> sp(new int(1)); SharedPtr<FILE,Fclose> sp1(fopen("test.txt","w"),Fclose()); SharedPtr<string,Free> sp3((string *)malloc(sizeof(string)),Free()); } int main() { test(); system("pause"); return 0; }
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。