<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    智能指針(一):STL auto_ptr實現原理

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    智能指針實際上是一個類(class),里面封裝了一個指針.它的用處是啥呢?

    指針與內存

    說到指針自然涉及到內存.我們如果是在堆棧(stack)中分配了內存,用完后由系統去負責釋放.如果是自定義類型,就會自動的去調用你的析構函數.

    但如果是在堆(heap)中分配了內存,也就是用malloc或者new.那只能自動手動的使用free或delete去釋放.所以使用heap時處理的不好很容易出現啥內存泄露(內存沒有釋放掉).或者如果你delete一次了,但沒讓它賦值為0,然后再delete一次就導致未定義行為了.

    于是你想如果系統能也像管理stack一樣來管理你的heap區域.不用再擔心內存的分配與釋放該多好啊.事實上Java,C#都這樣去做了.也給你去管理heap區域了(所有的自定義類型實例化時都去heap區域獲取內存了.也沒于提供指針的功能.你想自己去釋放內存都不給你這機會了.JVM或者CLR會在后臺自動的去給你釋放掉那些不用的內存.當然這樣一來效率自然沒有你手動釋放來的高了.)

    假如有一個指針指向一塊分配的內存,智能指針就是把該指針封裝起來,然后用完了會自動去釋放內存(通過智能指針類的析構函數).這樣你就不用擔心沒有去釋放內存了.當然并不是說你使用了智能指針就能像使用Java,C#一樣不用再擔心內存問題了.智能指針在使用的時候還會存在很多的問題.

    據說JVM,CRL也是用(c與c++)實現的.不知道那里面也有用到智能指針不.

     

    智能指針的實現

    如果你自己要封裝一個指針你會咋整呢?來來個初稿瞧瞧

    1.最精簡版本

    template< class T>

    class my_auto_ptr {

    public:

      T* m_ptr;  //被封裝的指針

    public:

     my_auto_ptr( T* p) :m_ptr( p ) { }   //構造函數

     ~my_auto_ptr() { delete m_ptr; }     //析構函數

    }

    上面的自然是最精簡版的,只一個成員變量,構造函數和析造函數.不過雖然簡單其實也能拿來用了啊.比如:

    my_auto_ptr<int> myPtr( new int(88) ); //等價int* ip = new int(88); 但這樣你得手動delete ip;而用了智能指針就不用手動delete了.

    cout<< *myPtr.m_ptr;   //相當于cout<<*ip;

     

    2.改進版本(重載運算符使類用起來像指針)

    上面的的精簡版本用起來還挺麻煩.我們是希望封裝了指針類用起來跟指針本身一樣才好.所以需要重載-> , * 等運算符

    template< class T>

    class my_auto_ptr {

    private:

    T* m_ptr; //被封裝的指針

    public:

    my_auto_ptr( T* p) :m_ptr( p ) { }

    ~my_auto_ptr() { delete m_ptr; }

    T& operator*() { return *m_ptr;}

    T*  operator->() { return m_ptr;}

    }

    現在my_auto_ptr可以變得很像指針了

    my_auto_ptr<int> mp(new int(88) );   //等價int* ip = new int(88);

    int num = *mp;   //等價int num = *ip;

    假如有這樣的類struct Arwen { void Test() { cout<"i am arwen"<<; }

    則my_auto_ptr<Arwen> mp( new Arwen);   //等價Arwen* ip = new Arwen;

      mp->Test();  //等價ip-Test();

     

     

    3.完善版本(復制構造)

    一個完善點的類往往還涉及到復制構造的一些操作.也可以做把另外一個智能指針類做為構造函數的參數,或者通過=給一個類賦值

    template< class T>

    class my_auto_ptr {

    private:

    T* m_ptr;

    T* GetPtr(){ //供構造賦值時使用

    T* tmp = m_ptr;

    m_ptr = 0;

    return tmp;

    }

    public:

    explicit my_auto_ptr( T* p = 0) :m_ptr( p ) { }

    ~my_auto_ptr() { delete m_ptr; }

    T& operator*() { return *m_ptr;}

    T* operator->() { return m_ptr;}

     

    my_auto_ptr(my_auto_ptr& mp){   //復制構造函數

    m_ptr = mp.GetPtr(); //mp復制過來后它自己原來的指針相當于失效了.

    }

    my_auto_ptr& operator=(my_auto_ptr& ap){ 造型賦值操作符

    if(ap != *this)

    {

    delete m_ptr;

    m_ptr = ap.GetPtr();

    }

    return *this;

    }

     

    void reset(T* p){  //指針重置,相當于把指針指向另外一個地方去

    if(p != m_ptr)

    delete m_ptr;

    m_ptr = p;

    }

    };

     

    使用舉例:

    如有類struct Arwen{

    int age;

    Arwen(int gg) :age(gg) { };

    };

     

    void main()

    {

     my_auto_ptr<Arwen> myPtr( new Arwen(24) );

    int num =myPtr->age; //正確

     

     my_auto_ptr<Arwen> ptrOne( myPtr);  //復制構造

     //num =myPtr->age; 該處會出錯.因為把myPtr復制給ptrOne后,它自己本身相當于失效了

      num = ptrOne->age; //正確

     

     my_auto_ptr<Arwen> ptrTwo = ptrOne;

     //num = ptrOne->age;該處也會出錯,此時ptrOne也失效了

     num = ptrTwo->age; //正確

     

    Arwen* pArwen = new Arwen( 88 );

    ptrTwo.reset( pArwen);

    num = pArwen->age; //此處的值是88了,而不是以前的24

     

    return 0;

    }

     

     

    auto_ptr的缺陷

    上面我實現的my_auto_ptr基本上是實現了auto_ptr的所有核心功能.從里面我們可以明顯的看到一個很大缺陷.我們看到當通過復構造函數,通過操作符=賦值后,原來的那個智能指針對象就失效了.只有新的智能指針對象可以有效使用了.用個專業點的說法叫所有權的轉移.被包裝的指針指向的內存塊就像是一份獨享占用的財產,當通過復制構造,通過=賦值傳給別的智能指針對象時,原有的對象就失去了對那塊內存區域的擁有權.也就是說任何時候只能有一個智能指針對象指向那塊內存區域,不能有兩個對象同時指向那塊內存區域.

    這樣一來auto_ptr不能做為STL中容器的元素,為啥呢? 因為容器中經常存在值拷貝的情況嘛,把一個容器對象直接賦值給另一對象.完了之后兩個容器對象可得都能用啊.而如果是auto_ptr的話顯然賦值后只能一個有用,另一個完全報廢了.另外比如你有個變量auto_ptr<int> ap( new int(44) );  然后ap被放進一個容器后,ap就報廢不能用了.

    不過沒辦法啊,在c++ 11標準之前,現在我們大部分用的是98標準吧,STL里面只有auto_ptr這一種智能指針.而在11標準中除了auto_ptr還有如下三種:

     

    unique_ptr

    smart pointer with unique object ownership semantics

    只能有一個主人的指針,可以用于STL容器

    shared_ptr

    smart pointer with shared object ownership semantics

    可共享的指針

    weak_ptr

    weak reference to an object managed by std::shared_ptr

    弱引用指針

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全