C++11--智慧指標詳解及實現
阿新 • • 發佈:2018-12-30
1、基礎概念
智慧指標的一種通用實現技術是使用引用計數。智慧指標類將一個計數器與智慧指標指向的物件相關聯,用來記錄有多少個智慧指標指向相同的物件,並在恰當的時候釋放物件。
每次建立類的新物件時,初始化指標並將引用計數置為1;當物件作為另一物件的副本而建立時,引用計數加1;對一個物件進行賦值時,賦值操作符減少左運算元所指物件的引用計數(如果引用計數為減至0,則刪除物件),並增加右運算元所指物件的引用計數;呼叫解構函式時,建構函式減少引用計數(如果引用計數減至0,則刪除基礎物件)。
下圖是shared_ptr的記憶體模型:
由圖中可以看到,實際上引用計數、自定義銷燬等都不是直接儲存在shared_ptr中,而是通過一個指標指向的一個控制塊儲存的,控制塊是動態分配的記憶體 。
下面是用類模板簡單實現shared_ptr.
#include <iostream> using namespace std; template<typename T> class SmartPointer { private: T* p_; size_t* count_; public: SmartPointer(T* ptr = nullptr) : p_(ptr) { if (p_) { count_ = new size_t(1); } else { count_ = new size_t(0); } } SmartPointer(const SmartPointer& ptr) { p_ = ptr.p_; count_ = ptr.count_; (*count_)++; } SmartPointer& operator=(const SmartPointer& ptr) { if (p_ == ptr.p_) { return *this; } if (p_) { if (--(*count_) == 0) { delete p_; delete count_; } } p_ = ptr.p_; count_ = ptr.count_; (*count_)++; return *this; } ~SmartPointer() { if (--(*count_) == 0) { delete p_; delete count_; } } size_t use_count() { return *count_; } }; int main() { SmartPointer<int> sp1(new int(10)); SmartPointer<int> sp2(sp1); SmartPointer<int> sp3(new int(20)); sp2 = sp3; std::cout << sp1.use_count() << std::endl; std::cout << sp3.use_count() << std::endl; }
2、智慧指標帶來的效能影響
1)shared_ptr的尺寸是裸指標的兩倍。
2)會帶來控制塊的開銷。
3)引用計數的遞增和遞減是原子操作,原子操作一般都比非原子操作慢。
3、使用weak_ptr解決shared_ptr的迴圈引用。
解決方案:將類A,B中的shared_prt改為weak_ptr即可,weak_ptr不會增加shared_ptr的引用計數
class B; class A { public: weak_ptr<B> p; //shared_ptr<B> p; }; class B { public: weak_ptr<A> p; //shared_ptr<A> p; }; int main() { while (true) { shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->p = pb; pb->p = pa; } return 0; }
參考文章: