<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>
  • 網站首頁 > 物聯資訊 > 技術分享

    auto_ptr,shared_ptr 智能指針的使用

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

    Q: 那個auto_ptr是什么東東啊?為什么沒有auto_array?
    A: 哦,auto_ptr是一個很簡單的資源封裝類,是在<memory>頭文件中定義的。它使用“資源分配即初始化”技術來保證資源在發生異常時也能被安全釋放(“exception safety”)。一個auto_ptr封裝了一個指針,也可以被當作指針來使用。當其生命周期到了盡頭,auto_ptr會自動釋放指針。例如:
     #include<memory>
     using namespace std;

     struct X {
      int m;
      // ..
     };

     void f()
     {
      auto_ptr<X> p(new X);
      X* q = new X;

      p->m++;  // use p just like a pointer
      q->m++;
      // ...

      delete q;
     }
    如果在代碼用// ...標注的地方拋出異常,那么p會被正常刪除——這個功勞應該記在auto_ptr的析構函數頭上。不過,q指向的X類型對象就沒有被釋放(因為不是用auto_ptr定義的)。詳情請見TC++PL 14.4.2節。
    Auto_ptr是一個輕量級的類,沒有引入引用計數機制。如果你把一個auto_ptr(比如,ap1)賦給另一個auto_ptr(比如,ap2),那么ap2將持有實際指針,而ap1將持有零指針。例如:

     #include<memory>
     #include<iostream>
     using namespace std;

     struct X {
      int m;
      // ..
     };

     int main()
     {
      auto_ptr<X> p(new X);
      auto_ptr<X> q(p);
      cout << "p " << p.get() << " q " << q.get() << "\n";
     }

     
    運行結果應該是先顯示一個零指針,然后才是一個實際指針,就像這樣: 
     p 0x0 q 0x378d0

     
    auto_ptr::get()返回實際指針。
    這里,語義似乎是“轉移”,而非“拷貝”,這或許有點令人驚訝。特別要注意的是,不要把auto_ptr作為標準容器的參數——標準容器要求通常的拷貝語義。例如:

     std::vector<auto_ptr<X> >v; // error

    一個auto_ptr只能持有指向單個元素的指針,而不是數組指針:

     void f(int n)
     {
      auto_ptr<X> p(new X[n]); // error
      // ...
     }

     
    上述代碼會出錯,因為析構函數是使用delete而非delete[]來釋放指針的,所以后面的n-1個X沒有被釋放。 
    那么,看來我們應該用一個使用delete[]來釋放指針的,叫auto_array的類似東東來放數組了?哦,不,不,沒有什么auto_array。理由是,不需要有啊——我們完全可以用vector嘛:

     void f(int n)
     {
      vector<X> v(n);
      // ...
     }

     
    如果在 // ... 部分發生了異常,v的析構函數會被自動調用。

    引入智能指針可以防止出現懸垂指針的情況
    一般是把指針封裝到一個稱之為智能指針類中,這個類中另外還封裝了一個使用計數器,對指針的復制等操作將導致該計數器的值加1,對指針的delete操作則會減1,值為0時,指針為NULL

    在C++中,內存資源的管理經常是一個令人頭痛的問題,指針的錯誤使用經常是造成內存泄露和“未定義行為”的根源。很多資源被動態分配與heap內而后被用于單一區塊或函數內。它們應該在控制流離開那個區塊或函數時被釋放。智能指針就是針對這種形勢而設計的特制產品。它是一種外觀和行為都被設計成與內建的指針相類似的對象,不過它提供更多的功能,其析構函數會自動對其所指的對象調用delete來進行刪除。

    常用的智能指針有auto_ptr(C++標準庫提供),shared_ptr(tr1庫提供,最為常用),另外還有scoped_ptr,intrusive_ptr,weak_ptr(均為tr1庫提供)。在此著重介紹auto_ptr以及shared_ptr兩種,在文章最后會對其他智能指針也進行簡單的介紹。

    1、auto_ptr:它允許程序員創建一個指向某種資源的指針對象,當該對象離開它的作用域時,它所指向的資源也會被自動釋放。在此類中對*和->運算符進行了重載,使它可以像指針一樣被使用,另外它也提供get(),reset(),release()等方法來供外界取出和重新設置它所指向的對象,詳細內容參考[5]以及C++標準庫的說明文檔。下面通過一個示例來展示auto_ptr的使用。
    [code=cpp]//文件名為test_auto_ptr.cpp
    //auto_ptr位于<memory>頭文件中

    #include <memory>
    #include <iostream>

    using namespace std;         
    class MyClass {
    public:
         int i;
       MyClass(int s) {i=s;}
       ~MyClass() {cout<<"This class has been destroied. "<<i<<endl;}
       void myFunc() {cout<<"myFunc() done. "<<i <<endl;}
    };            

    int main() {
       auto_ptr<MyClass> ptr1(new MyClass(1));            
       auto_ptr<MyClass>ptr2(new MyClass(2));
       ptr1->myFunc();          
       ptr2->myFunc();
       cout<<"test 1 done"<<endl;
        
       ptr2 = ptr1;
       ptr2->myFunc();          
       //ptr1->myFunc();//取消注釋會發生段錯誤或未定義結果
        cout<<"test 2 done"<<endl;
       
       MyClass* ptr = ptr2.get();          
       ptr->myFunc();           
         ptr2.reset(new MyClass(3));
       ptr2->myFunc();
       ptr->myFunc(); //此處會產生未定義的結果
       cout<<"test 3 done"<<endl;
       return 0;
    }    [/code]

    編譯并運行:

    #g++ -g -o test_auto_ptr test_auto_ptr.cpp

    # ./test_auto_ptr

    運行結果如下:
    myFunc() done. 1
    myFunc() done. 2
    test 1 done
    This class has been destroied. 2
    myFunc() done. 1
    test 2 done
    myFunc() done. 1
    This class has been destroied. 1
    myFunc() done. 3
    myFunc() done. 0
    test 3 done
    This class has been destroied. 3

    從上面的結果可以看出auto_ptr具有智能指針的功能,但是由于auto_ptr被銷毀時會自動刪除它所指之物,所以一定要注意不要讓多個auto_ptr同時指向同一對象,否則一個對象會被刪除多次,這會導致“未定義的行為”。另外,auto_ptr在進行復制時會產生一些詭異的行為,如進行ptr2=ptr1;之后ptr2指向對象,而ptr1會被設為NULL,調用ptr1會產生未定義行為(或段錯誤)。由此也可以看出auto_ptr不能用于STL容器中。

    2、shared_ptr:它是一種引用計數型智能指針,它的復制行為相比auto_ptr要正常許多,它也可以被自由用于STL容器中。但是shared_ptr類不屬于標準C++庫,而是屬于tr1庫(C++ tr1是針對C++標準庫的第一次擴展。即將到來的下一個版本的C++標準c++0x會包括它,以及一些語言本身的擴充),現在的編譯器對于tr1庫的支持良莠不齊,但是從gcc 4.0開始就實現了對于shared_ptr的支持。shared_ptr的用法和auto_ptr類似,具體參見[1] 。下面通過示例來介紹shared_ptr的使用:

    [code=cpp]//文件名為test_shared_ptr.cpp
    //shared_ptr位于 <tr1/memory> 頭文件中

    #include <tr1/memory>
    #include <iostream>
    #include<vector>
    using namespace std;
    using std::tr1::shared_ptr;         
    class MyClass {
    public:
       int i;
       MyClass(int s) {i=s;}
       ~MyClass() {cout<<"This class has been destroied. "<< i <<endl;}
       void myFunc() {cout<<"myFunc() done. "<< i <<endl;}
    };            

    int main() {

    //下面分別建立兩個智能指針,然后測試他們的基本使用
    //注意不能使用如下形式: shared_ptr<MyClass> ptr = new MyClass(2);
       shared_ptr<MyClass> ptr1(new MyClass(1));            
       shared_ptr<MyClass>ptr2(new MyClass(2));
       (*ptr1).myFunc();          
       ptr2->myFunc();
       cout<<"test 1 done!"<<endl;
        
        
         //下面嘗試復制操作,并進行把兩個
       ptr2 = ptr1;
       ptr2->myFunc();          
       ptr1->myFunc();
       ptr1.reset();
       cout<<"ptr1.reset() done!"<<endl;
       ptr2.reset();
       cout<<"test 2 done!"<<endl; 
         
          
       MyClass* temp_ptr=new MyClass(3);
       ptr1.reset(temp_ptr);//把普通指針委托給智能指針進行托管          
       ptr1->myFunc(); //注意委托之后不要使用delete,否則程序會出現異常,輕則出錯,重則掛掉
        //delete temp_ptr;         
       cout<<"test 3 done"<<endl;
      
      
       //智能指針也可以放入STL容器中,并且不影響其使用
       //注意這里MyClass> 后面有一個空格,否則會被當作一個>>運算符
       vector<shared_ptr<MyClass> > myVector;
             {
         shared_ptr<MyClass> temp_shared_ptr(new MyClass(4));
        myVector.push_back(temp_shared_ptr);
             }//離開temp_shared_ptr的作用域,只是它自己析構,MyClass并不會析構
      
       vector<shared_ptr<MyClass> >::iterator itor =myVector.begin();

       (*itor)->myFunc();
       myVector.clear();
       cout<<"test 4 done!"<<endl;

       return 0;
    }

    [/code]

    編譯并運行:

    # g++ -g -o test_shared_ptr test_shared_ptr.cpp

    #./test_shared_ptr

    運行結果如下:
    myFunc() done. 1
    myFunc() done. 2
    test 1 done!
    This class has been destroied. 2
    myFunc() done. 1
    myFunc() done. 1
    ptr1.reset() done!
    This class has been destroied. 1
    test 2 done!
    myFunc() done. 3
    test 3 done
    myFunc() done. 4
    This class has been destroied. 4
    test 4 done!
    This class has been destroied. 3

    從運行結果中也可以看出shared_ptr 具有很好的資源管理的能力,可以實現理想的復制操作,并且可以和STL容器兼容。在多線程情況下shared_ptr可以達到和c++內置類型同等的安全性。無疑shared_ptr類將是tr1中最常使用的類型。

    但是shared_ptr并不是盡善盡美的,它還存在環狀引用等問題。在使用shared_ptr時也有一些注意事項需要遵守,否則反而會弄巧成拙。文章[3]中指出了一些shared_ptr的缺點,不防也看看,有些地方說的還是有道理的。

    3、其他一些智能指針介紹

    scoped_ptr 與auto_ptr類似,但是不允許復制;
    intrusive_ptr是shared_ptr侵入式版本。使用情況,內部以及編寫好了自己的內部引用計算器的代碼,而又沒有時間重寫它。intrusive_ptr可以從this構造。
    weak_ptr是智能指針shared_ptr的觀察者。

    上面只是對于智能指針的一個簡單的介紹和示例的說明,我也是剛開始學習智能指針,希望上面的內容對大家有幫助。

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