淺談C++的智慧指標
我們使用智慧指標來自動執行管理記憶體,避免對原始指標的使用不當而造成記憶體洩漏。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C++裡可能出現的記憶體問題大致有這麼幾個方面:
1. 緩衝區溢位。
2. 空懸指標 / 野指標。
3. 重複釋放。
4. 記憶體洩漏。
5. 不配對的new[] / delete。
6. 記憶體碎片。
通過正確使用智慧指標很容易解決前面5個問題:
1. 緩衝區溢位:用std::vector<char> / srd::string 或自己編寫Buffer class 來管理緩衝區,自動記住用緩衝區的長度,並通過成員函式而不是裸指標來修改緩衝區。
2. 空懸指標 / 野指標:用shared_ptr / weak_ptr解決。
3. 重複釋放:用scoped_ptr,只在物件析構的時候釋放一次。 // unique_ptr
4. 記憶體洩漏:用scoped_ptr, 物件析構的時候自動釋放記憶體。 // unique_ptr
5. 不配對的new[] / delete:把new[] 統統替換為 std::vector。
-------------引用自 陳碩 《Linux多執行緒服務端程式設計》
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面介紹了這幾個智慧指標的使用:
一、通過std::shared_ptr這種智慧指標訪問的物件採用共享所有權來管理其生存期。即內部採用引用計數方式,只有當應用計數為0時,會釋放所指資源。
shared_ptr<string> p = make_shared<string>("apple");
我們儘可能使用std::make_shared而避免使用new 來建立物件。(可參考《Effective Modern C++》條款21.)
二、std::weak_ptr也是一個應用計數型智慧指標,但它不增加物件的引用次數,即弱引用。可以說是std::shared_ptr的一種擴充。weak_ptr不控制物件的生命期,但它知道物件是否還活著(呼叫lock()) 。
shared_ptr<string> p = make_shared<string>("apple"); weak_ptr<string> wp(p); shared_ptr<string> sp = wp.lock(); // 如果物件還存在,返回一個shared_ptr,其中包含weak_ptr物件保留的資訊。若死了,則返回一個空的shared_ptr。
if (sp) { } else { }
三、unique_ptr與shared_ptr不同的是unique_ptr對所管理的資源進行獨享,unique_ptr不允許對資源進行拷貝。用來取代std::auto_ptr,可以替換boost庫中的scoped_ptr。
unique_ptr<int> p1 = make_unique<int>(5); unique_ptr<int> p2(p1); // error unique_ptr<int> p3 = p1; // error
我們儘可能使用std::make_unique而避免使用new 來建立物件。(可參考《Effective Modern C++》條款21.)
測試程式碼(以shared_ptr為例智慧指標日常使用, 測試環境: VS2017):
#include <iostream> #include <memory> #include <string> using namespace std; class apple { public: apple(const string& s = "0") : number(s) { } string getString() const { return number; } private: string number; }; class decorate final { public: decorate() = delete; // 不允許單獨建立decorate物件 decorate(const shared_ptr<apple>& rhs) :pta(rhs){ } decorate(const decorate& rhs) : pta(make_shared<apple>(*rhs.pta)) { } decorate& operator=(const decorate& rhs); shared_ptr<apple> getPtr() const { return pta; } private: shared_ptr<apple> pta; }; decorate& decorate::operator= (const decorate& rhs) { if (this != &rhs) pta = rhs.pta; return *this; } int main() { shared_ptr<apple> pta = make_shared<apple>("yantai-apple"); decorate myDec(pta); cout << myDec.getPtr()->getString() << endl; return 0; }