1. 程式人生 > >淺談C++的智慧指標

淺談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;
}