不少人談到c++,說它特別難,可能有一部分就是由於c++的內存管理吧,不像java那樣有虛擬機動態的管理內存,在程序運行過程當中可能就會出現內存泄漏,然而這種問題其實均可以經過c++11引入的智能指針來解決,相反我還認爲這種內存管理仍是c++語言的優點,由於盡在掌握。java
c++11引入了三種智能指針:c++
shared_ptr使用了引用計數,每個shared_ptr的拷貝都指向相同的內存,每次拷貝都會觸發引用計數+1,每次生命週期結束析構的時候引用計數-1,在最後一個shared_ptr析構的時候,內存纔會釋放。app
使用方法以下:源碼分析
struct ClassWrapper { ClassWrapper() { cout << "construct" << endl; data = new int[10]; } ~ClassWrapper() { cout << "deconstruct" << endl; if (data != nullptr) { delete[] data; } } void Print() { cout << "print" << endl; } int* data; }; void Func(std::shared_ptr<ClassWrapper> ptr) { ptr->Print(); } int main() { auto smart_ptr = std::make_shared<ClassWrapper>(); auto ptr2 = smart_ptr; // 引用計數+1 ptr2->Print(); Func(smart_ptr); // 引用計數+1 smart_ptr->Print(); ClassWrapper *p = smart_ptr.get(); // 能夠經過get獲取裸指針 p->Print(); return 0; }
智能指針還能夠自定義刪除器,在引用計數爲0的時候自動調用刪除器來釋放對象的內存,代碼以下:post
std::shared_ptr<int> ptr(new int, [](int *p){ delete p; });
關於shared_ptr有幾點須要注意:優化
經過shared_from_this()返回this指針,不要把this指針做爲shared_ptr返回出來,由於this指針本質就是裸指針,經過this返回可能 會致使重複析構,不能把this指針交給智能指針管理。this
class A { shared_ptr<A> GetSelf() { return shared_from_this(); // return shared_ptr<A>(this); 錯誤,會致使double free } };
要避免循環引用,循環引用致使內存永遠不會被釋放,形成內存泄漏。spa
using namespace std; struct A; struct B; struct A { std::shared_ptr<B> bptr; ~A() { cout << "A delete" << endl; } }; struct B { std::shared_ptr<A> aptr; ~B() { cout << "B delete" << endl; } }; int main() { auto aaptr = std::make_shared<A>(); auto bbptr = std::make_shared<B>(); aaptr->bptr = bbptr; bbptr->aptr = aaptr; return 0; }
上面代碼,產生了循環引用,致使aptr和bptr的引用計數爲2,離開做用域後aptr和bptr的引用計數-1,可是永遠不會爲0,致使指針永遠不會析構,產生了內存泄漏,如何解決這種問題呢,答案是使用weak_ptr。指針
weak_ptr是用來監視shared_ptr的生命週期,它無論理shared_ptr內部的指針,它的拷貝的析構都不會影響引用計數,純粹是做爲一個旁觀者監視shared_ptr中管理的資源是否存在,能夠用來返回this指針和解決循環引用問題。c++11
做用2:解決循環引用問題。
struct A; struct B; struct A { std::shared_ptr<B> bptr; ~A() { cout << "A delete" << endl; } void Print() { cout << "A" << endl; } }; struct B { std::weak_ptr<A> aptr; // 這裏改爲weak_ptr ~B() { cout << "B delete" << endl; } void PrintA() { if (!aptr.expired()) { // 監視shared_ptr的生命週期 auto ptr = aptr.lock(); ptr->Print(); } } }; int main() { auto aaptr = std::make_shared<A>(); auto bbptr = std::make_shared<B>(); aaptr->bptr = bbptr; bbptr->aptr = aaptr; bbptr->PrintA(); return 0; } 輸出: A A delete B delete
std::unique_ptr是一個獨佔型的智能指針,它不容許其它智能指針共享其內部指針,也不容許unique_ptr的拷貝和賦值。使用方法和shared_ptr相似,區別是不能夠拷貝:
using namespace std; struct A { ~A() { cout << "A delete" << endl; } void Print() { cout << "A" << endl; } }; int main() { auto ptr = std::unique_ptr<A>(new A); auto tptr = std::make_unique<A>(); // error, c++11還不行,須要c++14 std::unique_ptr<A> tem = ptr; // error, unique_ptr不容許移動 ptr->Print(); return 0; }
unique_ptr也能夠像shared_ptr同樣自定義刪除器,使用方法和shared_ptr相同。
關於c++11的智能指針的使用就介紹到這裏,源碼分析能夠看我以前的文章https://www.jianshu.com/p/b6a...
你們有問題能夠聯繫我哦~
https://www.jianshu.com/p/b6a...
https://juejin.im/post/5dcaa8...
《深刻應用c++11:代碼優化與工程級應用》更多文章,請關注個人V X 公 主 號:程序喵大人,歡迎交流。