乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C++智能指針auto

       torony 2016-01-02

             對(duì)于C/C++程序員來說, 內(nèi)存泄露是一個(gè)談之色變的話題, 很多時(shí)候, 機(jī)器運(yùn)行1天2天都是ok的, 但運(yùn)行到一個(gè)星期后, 就卡得要死。 實(shí)際上, 很多時(shí)候是內(nèi)存泄露造成的。 內(nèi)存泄露很容易引入, 但是定位起來非常非常難, 在內(nèi)存泄露初期, 通常沒有異常癥狀, 但隨著內(nèi)存泄露的累積, 內(nèi)存逐漸被啃光, 最終導(dǎo)致卡死或者死機(jī)。


             申請(qǐng)堆內(nèi)存, 又沒有正確釋放, 就會(huì)導(dǎo)致內(nèi)存泄露, 聽起來好可怕啊, 那有沒有什么辦法可以解決這一難題呢? 有的! 人類的智慧還是很厲害的。 我么知道, 棧對(duì)象在離開其作用域的時(shí)候, 會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù), 所以, 可以考慮把某一棧對(duì)象與某一堆內(nèi)存綁定,且在其析構(gòu)函數(shù)中釋放堆內(nèi)存,  那么, 在該棧對(duì)象離開作用域時(shí), 堆內(nèi)存自動(dòng)釋放, 這就是智能指針(本質(zhì)是棧對(duì)象)的原理,簡直是妙招啊。  這個(gè)棧對(duì)象裝得像指針一樣, 所以我們稱之為智能指針, 其實(shí), 它不過就是個(gè)普通的棧對(duì)象而已。 


              在本文中, 我們來介紹智能指針中的一種------auto_ptr,  并從源碼的角度來看看auto_ptr使用中存在的一些常見問題:


             我們先來看一段簡單的程序:

      1. #include <iostream>  
      2. #include <memory> // 有auto_ptr這個(gè)類模板  
      3. using namespace std;  
      4.   
      5. int main()  
      6. {  
      7.     auto_ptr<int> p(new int(100));  
      8.   
      9.     // p是個(gè)對(duì)象, 但重載了*運(yùn)算符, 所以我說它很能裝, 裝得像個(gè)指針  
      10.     cout << *p << endl; // 100  
      11.   
      12.     return 0;  
      13. }  


            C++是一門復(fù)雜的語言, 比這個(gè)更糟糕的是: 一些不合格的C++程序員正在用它。 我們看看上面的程序, 實(shí)際上, 編譯器做了太多的手腳, 這也是C++復(fù)雜的一個(gè)原因。 我們展開memory文件, 看看其中關(guān)于auto_ptr的代碼, 復(fù)制過來, 然后形成如下程序:

      1. #include <iostream>  
      2. using namespace std;  
      3.   
      4.   
      5. // 微軟能把代碼寫成這樣, 也是夠風(fēng)騷的  
      6.   
      7.         // TEMPLATE CLASS auto_ptr  
      8. template<class _Ty>  
      9.     class auto_ptr {  
      10. public:  
      11.     typedef _Ty element_type;  
      12.     explicit auto_ptr(_Ty *_P = 0) _THROW0()  
      13.         : _Owns(_P != 0), _Ptr(_P) {}  
      14.     auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()  
      15.         : _Owns(_Y._Owns), _Ptr(_Y.release()) {}  
      16.     auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()  
      17.         {if (this != &_Y)  
      18.             {if (_Ptr != _Y.get())  
      19.                 {if (_Owns)  
      20.                     delete _Ptr;  
      21.                 _Owns = _Y._Owns; }  
      22.             else if (_Y._Owns)  
      23.                 _Owns = true;  
      24.             _Ptr = _Y.release(); }  
      25.         return (*this); }  
      26.     ~auto_ptr()  
      27.         {if (_Owns)  
      28.             delete _Ptr; }  
      29.     _Ty& operator*() const _THROW0()  
      30.         {return (*get()); }  
      31.     _Ty *operator->() const _THROW0()  
      32.         {return (get()); }  
      33.     _Ty *get() const _THROW0()  
      34.         {return (_Ptr); }  
      35.     _Ty *release() const _THROW0()  
      36.         {((auto_ptr<_Ty> *)this)->_Owns = false;  
      37.         return (_Ptr); }  
      38. private:  
      39.     bool _Owns;  
      40.     _Ty *_Ptr;  
      41.     };  
      42.   
      43.   
      44. int main()  
      45. {  
      46.     auto_ptr<int> p(new int(100));  
      47.   
      48.     // p是個(gè)對(duì)象, 但重載了*運(yùn)算符, 所以我說它很能裝, 裝得像個(gè)指針  
      49.     cout << *p << endl; // 100  
      50.   
      51.     return 0;  
      52. }  
             看了上面auto_ptr的源碼, 正在喝水的我, 差點(diǎn)嗆著了。 并想問: 微軟, 你還能再風(fēng)騷一點(diǎn)么疑問


             好吧, 我也懶得計(jì)較了。 于是, 對(duì)上面代碼進(jìn)行風(fēng)格整理, 并作出詳細(xì)的注釋, 就算是剖析一下auto_ptr的源碼吧:

      1. #include <iostream>  
      2. using namespace std;  
      3.   
      4.   
      5. // 簡單類  
      6. class A  
      7. {  
      8. public:  
      9.     void fun()  
      10.     {  
      11.       
      12.     }  
      13. };  
      14.   
      15.   
      16. template<class T>  
      17.   
      18. // 類模板  
      19. class auto_ptr   
      20. {  
      21. public:  
      22.   
      23.     // explicit構(gòu)造函數(shù), 禁止隱式轉(zhuǎn)化  
      24.     explicit auto_ptr(T *p = 0) throw()  
      25.         : m_bIsOwner(p != 0), m_ptr(p)   
      26.     {  
      27.         cout << "debug1" << endl;  
      28.     }  
      29.   
      30.     // owner轉(zhuǎn)移  
      31.     auto_ptr(const auto_ptr<T>& y) throw()  
      32.         : m_bIsOwner(y.m_bIsOwner), m_ptr(y.release())   
      33.     {  
      34.         cout << "debug2" << endl;  
      35.     }  
      36.   
      37.     // owner轉(zhuǎn)移  
      38.     auto_ptr<T>& operator=(const auto_ptr<T>& y) throw()  
      39.     {  
      40.         cout << "debug3" << endl;  
      41.   
      42.         if (this != &y) // 當(dāng)前對(duì)象不是y對(duì)象  
      43.         {  
      44.             cout << "debug4" << endl;  
      45.   
      46.             if (m_ptr != y.get()) // 當(dāng)前對(duì)象綁定的地址不是y對(duì)象綁定的地址  
      47.             {  
      48.                 cout << "debug5" << endl;  
      49.   
      50.                 if (m_bIsOwner) // 如果當(dāng)前對(duì)象已經(jīng)綁定堆, 則要先釋放  
      51.                 {  
      52.                     cout << "debug6" << endl;  
      53.                     delete m_ptr;  
      54.                 }  
      55.   
      56.                 cout << "debug7" << endl;  
      57.   
      58.                 m_bIsOwner = y.m_bIsOwner; // 轉(zhuǎn)移owner  
      59.             }  
      60.             else if (y.m_bIsOwner) // 當(dāng)前對(duì)象與y綁定到同一塊堆上, 且y是owner, 則把y的owner轉(zhuǎn)移給當(dāng)前對(duì)象  
      61.             {  
      62.                 cout << "debug8" << endl;  
      63.   
      64.                 m_bIsOwner = true;  
      65.             }  
      66.   
      67.             cout << "debug9" << endl;  
      68.   
      69.             m_ptr = y.release();  // 讓y不再是owner  
      70.         }  
      71.   
      72.         cout << "debug10" << endl;  
      73.   
      74.         return *this;  // 返回當(dāng)前對(duì)象的引用  
      75.     }  
      76.   
      77.     // 析構(gòu)函數(shù)  
      78.     ~auto_ptr()  
      79.     {  
      80.         cout << "debug11" << endl;    
      81.   
      82.         if (m_bIsOwner) // 只有擁有owner屬性才釋放堆, 這樣避免重復(fù)釋放  
      83.         {  
      84.             cout << "debug12" << endl;  
      85.   
      86.             delete m_ptr;  // 即使m_ptr是空指針也木有關(guān)系  
      87.         }  
      88.     }  
      89.   
      90.     // 重載對(duì)象的*運(yùn)算符, 使得對(duì)象"看起來"像指針, 可以執(zhí)行*p操作  
      91.     T& operator*() const throw()  
      92.     {  
      93.         cout << "debug13" << endl;  
      94.   
      95.         return *get();   
      96.     }  
      97.   
      98.     // 重載對(duì)象的->運(yùn)算符  
      99.     T *operator->() const throw()  
      100.     {  
      101.         cout << "debug14" << endl;  
      102.   
      103.         return get();   
      104.     }  
      105.   
      106.     // 獲得對(duì)象綁定的地址  
      107.     T *get() const throw()  
      108.     {  
      109.         cout << "debug15" << endl;  
      110.   
      111.         return m_ptr;   
      112.     }  
      113.   
      114.     // 去掉對(duì)象的owner屬性  
      115.     T *release() const throw()  
      116.     {  
      117.         cout << "debug16" << endl;  
      118.   
      119.         ((auto_ptr<T> *)this)->m_bIsOwner = false;  
      120.         return m_ptr;   
      121.     }  
      122.       
      123. private:  
      124.     bool m_bIsOwner;  // 對(duì)象是否擁有為owner的標(biāo)志  
      125.     T *m_ptr; // 對(duì)象綁定的指針  
      126. };  
      127.   
      128.   
      129. int main()  
      130. {  
      131.     {  
      132.         cout << "------------------------------" << endl;  
      133.   
      134.         // 用法錯(cuò)誤, 因?yàn)闃?gòu)造函數(shù)中有explicit, 不允許類型轉(zhuǎn)化  
      135.         //auto_ptr<int> p = new int(10);  
      136.     }  
      137.   
      138.   
      139.     {  
      140.         cout << "------------------------------" << endl;  
      141.   
      142.         // ok  
      143.         auto_ptr<int> p(new int(10));  
      144.     }  
      145.   
      146.   
      147.     {     
      148.         cout << "------------------------------" << endl;  
      149.   
      150.         // 下面代碼有嚴(yán)重的運(yùn)行期錯(cuò)誤, 實(shí)際上是嘗試delete棧上的內(nèi)容  
      151.         int a = 10;  
      152.         //auto_ptr<int> p(&a);  
      153.     }  
      154.   
      155.   
      156.     {     
      157.         cout << "------------------------------" << endl;  
      158.   
      159.         auto_ptr<int> p(new int(10));  
      160.   
      161.         // 錯(cuò)誤, p雖然"看似像"指針, 其本質(zhì)是對(duì)象, delete p;是未定義行為  
      162.         //delete p;  
      163.     }  
      164.   
      165.   
      166.     {     
      167.         cout << "------------------------------" << endl;  
      168.   
      169.         int *q = new int(10);  
      170.         auto_ptr<int> p(q);  
      171.   
      172.         // 錯(cuò)誤, q釋放一次, p釋放一次, 重復(fù)釋放啊  
      173.         //delete q;  
      174.     }  
      175.   
      176.   
      177.     {     
      178.         cout << "------------------------------" << endl;  
      179.   
      180.         auto_ptr<int> p0;  
      181.   
      182.         // 有debug3的打印, 但沒有debug4, 知道原因了吧  
      183.         p0 = p0;  
      184.     }  
      185.   
      186.   
      187.     {         
      188.         cout << "------------------------------" << endl;  
      189.   
      190.         auto_ptr<int> p0(new int(10));  
      191.   
      192.         // 注意, 這是初始化, 不是復(fù)制, 所以不會(huì)有debug3的打印  
      193.         auto_ptr<int> p1 = p0;   
      194.     }  
      195.   
      196.   
      197.     {         
      198.         cout << "------------------------------" << endl;  
      199.   
      200.         auto_ptr<int> p0(new int(10));  
      201.         auto_ptr<int> p1;   
      202.   
      203.         // 注意, 這才是賦值, 所有有debug3, debug4, debug5, debug7, debug9, debug10的打印  
      204.         // 為什么沒有debug6呢? 因?yàn)楫?dāng)前對(duì)象p1還不是owner  
      205.         p1 = p0;  
      206.     }  
      207.   
      208.   
      209.     {         
      210.         cout << "------------------------------" << endl;  
      211.   
      212.         auto_ptr<int> p0(new int(10));  
      213.         auto_ptr<int> p1(new int(20));  
      214.           
      215.         // 有debug6的打印, 因?yàn)楫?dāng)先釋放p1綁定的對(duì)象, 否則內(nèi)存又泄露了啊  
      216.         p1 = p0;  
      217.     }  
      218.   
      219.   
      220.     {         
      221.         cout << "------------------------------" << endl;  
      222.   
      223.         auto_ptr<int> p0(new int(10));  
      224.   
      225.         // 把owner轉(zhuǎn)給p1  
      226.         auto_ptr<int> p1(p0);  
      227.   
      228.         // 終于見到你了, debug8  
      229.         p0 = p1;  
      230.     }  
      231.   
      232.     {         
      233.         cout << "------------------------------" << endl;  
      234.   
      235.         auto_ptr<int> p(new int(10));  
      236.   
      237.         // 見到你了, debug13  
      238.         cout << *p << endl;  
      239.     }  
      240.   
      241.       
      242.     {         
      243.         cout << "------------------------------" << endl;  
      244.   
      245.         auto_ptr<A> p(new A());  
      246.   
      247.         // 終于見到你了, debug15  
      248.         p->fun();  
      249.     }  
      250.   
      251.   
      252.     {         
      253.         cout << "------------------------------" << endl;  
      254.   
      255.         auto_ptr<int> p0(new int(10));  
      256.         auto_ptr<int> p1(p0);  
      257.         auto_ptr<int> p2(p1);  
      258.   
      259.         // 實(shí)際上, p3才是最后的winner, 才是最后的owner, 所以釋放堆的重任在p3身上  
      260.         auto_ptr<int> p3(p2);  
      261.     }  
      262.   
      263.   
      264.     {         
      265.         cout << "------------------------------" << endl;  
      266.   
      267.         // oh, my god, 內(nèi)存泄露, 本來要delete [] q; 現(xiàn)在析構(gòu)函數(shù)只執(zhí)行delete q;  
      268.         int *q = new int[3];  
      269.         auto_ptr<int> p(q);  
      270.     }  
      271.   
      272.   
      273.     {         
      274.         cout << "------------------------------" << endl;  
      275.   
      276.         // oh, my god, 內(nèi)存泄露, 本來要delete [] q; 現(xiàn)在析構(gòu)函數(shù)只執(zhí)行delete q;  
      277.         int *q = new int[3];  
      278.         auto_ptr<int> p(q);  
      279.   
      280.         // 已經(jīng)說過, 下面語句會(huì)造成內(nèi)存重復(fù)釋放  
      281.         //delete q;  
      282.     }  
      283.   
      284.   
      285.     // 最后說明一下,  auto_ptr不適合做容器的元素, 這一點(diǎn)我們以后會(huì)再次討論到  
      286.   
      287.   
      288.     return 0;  
      289. }  
          
             好了, 不多說auto_ptr了, 一切盡在代碼中。




        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多