C++內存管理之智能指針

使用C++,最重要的一塊技能就是內存的分配和管理。這也是C/C++ 中陷阱最多的地方。說來慚愧,我曾經寫過一個獲取網卡信息的接口,有一個返回分支沒有調用free函數釋放資源,運行時間常了之後,進程佔用的內存越來越大。後來自己總結,要避免這種錯誤的發生,一個是自身要檢查好代碼,可以使用其他輔助工具如 靜態代碼檢查工具CppCheck 和 內存泄漏valgrid等。
對於JAVA開發,就不必花那麼多精力去關心內存問題。C++ 在這塊的改進最明顯的就是引入了智能指針,不必再擔心是否忘記釋放內存。一些搞跨平臺開發的項目對這個可能要求不高,因爲工程可能要兼容很多平臺,有些平臺的C++運行環境未必支持指針,但這畢竟不是主流,智能指針還是要了解一下的。
我曾經寫過一個函數追蹤的類,大概功能是,在要追蹤的函數裏面聲明一個追蹤類對象,然後把函數名 __ FUNC_NAME __ 作爲初始化參數傳遞進去。這個tracer類,內部只實現構造和析構。因爲函數開始的時候,對象開始構造,函數結束之前銷燬對象。在構造函數中,打印一句func_name 開始了,析構函數中打印一句, func_name結束了。這裏面的一個原理,是棧變量離開作用域時,會自動銷燬。智能指針本質上是一個對象,它重載了*和->運算符,在行爲上和普通指針的使用相同。爲了兼容不同類型,裏面用到了模板技術。
STL提供的智能指針有四種,auto_ptr, unique_ptr, share_ptr, weak_ptr, 瞭解了他們之間的關係就很容易記住和使用。使用這四個指針,需要引入頭文件

#include <memory>
using namespace std;
  1. auto_ptr實現了智能指針的基本功能,但是當右值時,會被剝奪資源,再次訪問時,易出錯。現在C++11,已明確廢棄,不提倡使用了。
    auto_ptr<int> a1(new int(1));
    auto_ptr<int> a2 = a1;
    // get函數返回真正的指針
    if(a1.get() == NULL)
        cout << "a1 is null"<<endl;
    else
        cout<<*a1<<endl;

    if(a2.get() == NULL)
        cout << "a2 is null"<<endl;
    else
        cout<<*a2<<endl;
  1. unique_ptr 是解決了auto_ptr的問題,它不允許賦值給其他智能指針. unique_ptr獨佔資源所有權,離開作用域時,釋放資源。
    unique_ptr<int> u1(new int(5));
    //unique_ptr<int> u2 = u1;  //error
    //unique_ptr<int> u3(u1);   //error
    cout<<*u1<<endl;
    auto us = make_unique<Simple>();// C++ 14
  1. shared_ptr 用來解決共享資源的情況,它內部採用了引用計數。
    shared_ptr<int> s1(new int(6));
    shared_ptr<int> s2 = s1;
    shared_ptr<int> s3(s1);
    cout<<*s1<<endl;
    cout<<*s2<<endl;
    cout<<*s3<<endl;
    cout<<s1.use_count()<<endl;//返回引用計數數量
  1. weak_ptr的引入是爲了解決shared_ptr中兩個或以上類相互包含,造成死鎖,無法使引用計數歸零的情況。weak_ptr並不會使引用數量增加。注意,weak_ptr不能直接調用成員函數,要使用lock() 返回一個shared_ptr智能指針,然後纔可以調用成員函數。
class SampleB;
class SampleA
{
public:
    shared_ptr<SampleB> psb;
    void echo()
    {
        cout<<"I am SampleA"<<endl;
    }

    ~SampleA()
    {
        cout<<"~SampleA" << endl;
    }
};
class SampleB
{
public:
    //shared_ptr<SampleA> psa;
    weak_ptr<SampleA> psa;
    ~SampleB()
    {
        cout<<"~SampleB" << endl;
    }
};


int main()
{
    shared_ptr<SampleB> pb(new SampleB());
    shared_ptr<SampleA> pa(new SampleA());
    pb->psa = pa;
    pa->psb = pb;
    cout<<pb.use_count()<<endl;
    cout<<pa.use_count()<<endl;
    pb->psa.lock()->echo();
    return 0;
}

上面就是C++提供四個智能指針, 使用起來和普通指針相似,很容易上手。

auto_ptr,C++11 已廢棄
shared_ptr,unique_ptr,weak_ptr C++11加入
make_unique C++14

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章