青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-341  評(píng)論-2670  文章-0  trackbacks-0

    復(fù)雜的東西寫多了,如今寫點(diǎn)簡(jiǎn)單的好了。由于功能上的需要,Vczh Library++3.0被我搞得很離譜。為了開發(fā)維護(hù)的遍歷、減少粗心犯下的錯(cuò)誤以及增強(qiáng)單元測(cè)試、回歸測(cè)試和測(cè)試工具,因此記錄下一些開發(fā)上的小技巧,以便拋磚引玉,造福他人。歡迎高手來(lái)噴,菜鳥膜拜。

    今天是關(guān)于內(nèi)存的最后一篇了。上一篇文章講了為什么不能對(duì)一個(gè)東西隨便memset。里面的demo代碼出了點(diǎn)小bug,不過(guò)我不喜歡在發(fā)文章的時(shí)候里面的demo代碼也拿去編譯和運(yùn)行,所以大家有什么發(fā)現(xiàn)的問(wèn)題就評(píng)論吧。這樣也便于后來(lái)的人不會(huì)受到誤導(dǎo)。這次說(shuō)的仍然是構(gòu)造函數(shù)和析構(gòu)函數(shù)的事情,不過(guò)我們將通過(guò)親手開發(fā)一個(gè)智能指針的方法,知道引用計(jì)數(shù)如何幫助管理資源,以及錯(cuò)誤使用引用計(jì)數(shù)的情況。

    首先先來(lái)看一下智能指針是如何幫助我們管理內(nèi)存的。現(xiàn)在智能指針的實(shí)現(xiàn)非常多,我就假設(shè)這個(gè)類型叫Ptr<T>吧。這跟Vczh Library++ 3.0所使用的實(shí)現(xiàn)一樣。

 1 class Base
 2 {
 3 public:
 4   virtual ~Base(){}
 5 };
 6 
 7 class Derived1 : public Base
 8 {
 9 };
10 
11 class Derived2 : public Base
12 {
13 };
14 
15 //---------------------------------------
16 
17 List<Ptr<Base>> objects;
18 objects.Add(new Derived1);
19 objects.Add(new Derived2);
20 
21 List<Ptr<Base>> objects2;
22 objects2.Add(objects[0]);

    當(dāng)然這里的List也是Vczh Library++3.0實(shí)現(xiàn)的,不過(guò)這玩意兒跟vector也好跟C#的List也好都是一個(gè)概念,因此也就不需要多加解釋了。我們可以看到智能指針的一個(gè)好處,只要沒(méi)有循環(huán)引用出現(xiàn),你無(wú)論怎么復(fù)制它,最終總是可以被析構(gòu)掉的。另一個(gè)例子告訴我們智能指針如何處理類型轉(zhuǎn)換:
1 Ptr<Derived1> d1=new Derived1;
2 Ptr<Base> b=d1;
3 Ptr<Derived2> d2=b.Cast<Derived2>();
4 // d2是空,因?yàn)閎指向的是Derived1而不是Derived2。

    這就如同我們Derived1*可以隱式轉(zhuǎn)換到Base*,而當(dāng)你使用dynamic_cast<Derived2*>(static_cast<Base*>(new Derived1))會(huì)得到0一樣。智能指針在幫助我們析構(gòu)對(duì)象的同時(shí),也要做好類型轉(zhuǎn)換的工作。

    好了,現(xiàn)在先讓我們一步一步做出那個(gè)Ptr<T>。我們需要清楚這個(gè)智能指針?biāo)獙?shí)現(xiàn)的功能是什么,然后我們一個(gè)一個(gè)來(lái)做。首先讓我們列出一張表:
    1、沒(méi)有參數(shù)構(gòu)造的時(shí)候,初始化為空
    2、使用指針構(gòu)造的時(shí)候,擁有那個(gè)指針,并且在沒(méi)有任何智能指針指向那個(gè)指針的時(shí)候刪除掉該指針。
    3、智能指針進(jìn)行復(fù)制的時(shí)候,兩個(gè)智能指針共同擁有該內(nèi)部指針。
    4、智能指針可以使用新的智能指針或裸指針重新賦值。
    5、需要支持隱式指針類型轉(zhuǎn)換,static_cast不支持而dynamic_cast支持的轉(zhuǎn)換則使用Cast<T2>()成員函數(shù)來(lái)解決。
    6、如果一個(gè)裸指針直接用來(lái)創(chuàng)建兩個(gè)智能指針的話,期望的情況是當(dāng)兩個(gè)智能指針析構(gòu)掉的時(shí)候,該指針會(huì)被delete兩次從而崩潰。
    7、不處理循環(huán)引用。

    最后兩點(diǎn)實(shí)際上是錯(cuò)誤使用智能指針的最常見(jiàn)的兩種情況。我們從1到5一個(gè)一個(gè)實(shí)現(xiàn)。首先是1。智能指針可以隱式轉(zhuǎn)換成bool,可以通過(guò)operator->()拿到內(nèi)部的T*。在沒(méi)有使用參數(shù)構(gòu)造的時(shí)候,需要轉(zhuǎn)換成false,以及拿到0:
 1 template<typename T>
 2 class Ptr
 3 {
 4 private:
 5   T* pointer;
 6   int* counter;
 7 
 8   void Increase()
 9   {
10     if(counter)++*counter;
11   }
12 
13   void Decrease()
14   {
15     if(counter && --*counter==0)
16     {
17       delete counter;
18       delete pointer;
19       counter=0;
20       pointer=0;
21     }
22   }
23 
24 public:
25   Ptr():pointer(0),counter(0)
26   {
27   }
28 
29   ~Ptr()
30   {
31     Decrease();
32   }
33 
34   operator bool()const
35   {
36     return counter!=0;
37   }
38 
39   T* operator->()const
40   {
41     return pointer;
42   }
43 };

    在這里我們實(shí)現(xiàn)了構(gòu)造函數(shù)和析構(gòu)函數(shù)。構(gòu)造函數(shù)把內(nèi)部指針和引用計(jì)數(shù)的指針都初始化為空,而析構(gòu)函數(shù)則進(jìn)行引用計(jì)數(shù)的減一操作。另外兩個(gè)操作符重載很容易理解。我們主要來(lái)看看Increase函數(shù)和Decrease函數(shù)都分別做了什么。Increase函數(shù)在引用計(jì)數(shù)存在的情況下,把引用計(jì)數(shù)加一。而Decrease函數(shù)在引用計(jì)數(shù)存在的情況下,把引用計(jì)數(shù)減一,如果引用計(jì)數(shù)在減一過(guò)程中變成了0,則刪掉擁有的資源。

    當(dāng)然到了這個(gè)時(shí)候智能指針還不能用,我們必須替他加上復(fù)制構(gòu)造函數(shù),operator=操作符重載以及使用指針賦值的情況。首先讓我們來(lái)看使用指針賦值的話我們應(yīng)該加上什么:
 1   Ptr(T* p):pointer(0),counter(0)
 2   {
 3     *this=p;
 4   }
 5 
 6   Ptr<T>& operator=(T* p)
 7   {
 8     Decrease();
 9     if(p)
10     {
11       pointer=p;
12       counter=new int(1);
13     }
14     else
15     {
16       pointer=0;
17       counter=0;
18     }
19     return *this;
20   }

    這里還是偷工減料了的,構(gòu)造函數(shù)接受了指針的話,還是轉(zhuǎn)給operator=去調(diào)用了。當(dāng)一個(gè)智能指針被一個(gè)新指針賦值的時(shí)候,我們首先要減掉一個(gè)引用計(jì)數(shù),因?yàn)樵瓉?lái)的指針再也不被這個(gè)智能指針共享了。之后就進(jìn)行判斷,如果來(lái)的是0,那么就變成空。如果不是0,就擁有該指針,引用計(jì)數(shù)初始化成1。于是我們就可以這么使用了:
1 Ptr<Base> b=new Derived1;
2 Ptr<Derived2> d2=new Derived2;

    讓我們開始復(fù)制他們吧。復(fù)制的要領(lǐng)是,先把之前擁有的指針脫離掉,然后連接到一個(gè)新的智能指針上面去。我們知道非空智能指針有多少個(gè),總的引用計(jì)數(shù)的和就是多少,只是分配到各個(gè)指針上面的數(shù)字不一樣而已:
 1   Ptr(const Ptr<T>& p):pointer(p.pointer),counter(p.counter)
 2   {
 3     Increase();
 4   }
 5 
 6   Ptr<T>& operator=(const Ptr<T>& p)
 7   {
 8     if(this!=&p)
 9     {
10       Decrease();
11       pointer=p.pointer;
12       counter=p.counter;
13       Increase();
14     }
15     return *this;
16   }

    在上一篇文章有朋友指出重載operator=的時(shí)候需要考慮是不是自己賦值給自己,其實(shí)這是很正確的。我們寫每一類的時(shí)候,特別是當(dāng)類擁有自己控制的資源的時(shí)候,需要非常注意這件事情。當(dāng)然如果只是復(fù)制幾個(gè)對(duì)象而不會(huì)new啊delete還是close什么handle,那檢查不檢查也無(wú)所謂了。在這里我們非常清楚,當(dāng)增加一個(gè)新的非空智能指針的時(shí)候,引用計(jì)數(shù)的總和會(huì)加一。當(dāng)修改一個(gè)非空智能指針的結(jié)果也是非空的時(shí)候,引用計(jì)數(shù)的和保持不變。當(dāng)然這是應(yīng)該的,因?yàn)槲覀冃枰谒蟹强罩悄苤羔樁急粴У舻臅r(shí)候,釋放受保護(hù)的所有資源。

    到了這里一個(gè)智能指針基本上已經(jīng)能用了,但是還不能處理父類子類的情況。這個(gè)是比較麻煩的,一個(gè)Ptr<Derived>事實(shí)上沒(méi)有權(quán)限訪問(wèn)Ptr<Base>的內(nèi)部對(duì)象。因此我們需要通過(guò)友元類來(lái)解決這個(gè)問(wèn)題。現(xiàn)在讓我們來(lái)添加兩個(gè)新的函數(shù)吧,從一個(gè)任意的Ptr<C>復(fù)制到Ptr<T>,然后保證只有當(dāng)C*可以隱式轉(zhuǎn)換成T*的時(shí)候編譯能夠通過(guò):
 1   template<X> friend class Ptr;
 2 
 3   template<typename C>
 4   Ptr(const Ptr<C>& p):pointer(p.pointer),counter(p.counter)
 5   {
 6     Increase();
 7   }
 8 
 9   template<typename C>
10   Ptr<T>& operator=(const Ptr<C>& p)
11   {
12     Decrease();
13     pointer=p.pointer;
14     counter=p.counter;
15     Increase();
16     return *this;
17   }

    注意這里我們的operator=并不用檢查是不是自己給自己賦值,因?yàn)檫@是兩個(gè)不同的類,相同的話會(huì)調(diào)用上面那個(gè)operator=的。如果C*不能隱式轉(zhuǎn)換到T*的話,這里的pointer=p.pointer就會(huì)失敗,從而滿足了我們的要求。

    現(xiàn)在我們能夠做的事情就更多了:
1 Ptr<Derived1> d1=new Derived1;
2 Ptr<Base> b=d1;

    于是我們只剩下最后一個(gè)Cast函數(shù)了。這個(gè)函數(shù)內(nèi)部使用dynamic_cast來(lái)做判斷,如果轉(zhuǎn)換失敗,會(huì)返回空指針:
 1   tempalte<typename C>
 2   Ptr<C> Cast()const
 3   {
 4     C* converted=dynamic_cast<C*>(pointer);
 5     Ptr<C> result;
 6     if(converted)
 7     {
 8       result.pointer=converted;
 9       result.counter=counter;
10       Increase();
11     }
12     return result;
13   }

    這是一種hack的方法,平時(shí)是不鼓勵(lì)的……不過(guò)因?yàn)椴僮鞯亩际荘tr,而且特化Ptr也是使用錯(cuò)誤的一種,所以這里就不管了。我們會(huì)檢查dynamic_cast的結(jié)果,如果成功了,那么會(huì)返回一個(gè)非空的新智能指針,而且這個(gè)時(shí)候我們也要記住Increase一下。

    好了,基本功能就完成了。當(dāng)然一個(gè)智能指針還要很多其他功能,譬如說(shuō)比較什么的,這個(gè)就你們自己搞定哈。

    指針和內(nèi)存就說(shuō)到這里了,下一篇講如何利用一個(gè)好的IDE構(gòu)造輕量級(jí)單元測(cè)試系統(tǒng)。我們都說(shuō)好的工具能夠提高生產(chǎn)力,因此這種方法不能脫離一個(gè)好的IDE使用。
posted on 2010-06-23 23:03 陳梓瀚(vczh) 閱讀(9889) 評(píng)論(15)  編輯 收藏 引用 所屬分類: C++實(shí)用技巧

評(píng)論:
# re: C++實(shí)用技巧(三) 2010-06-24 23:22 | zuhd
全文可以理解為一段共享內(nèi)存的故事  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 05:31 | SonicLing
效率存在問(wèn)題。
12 counter=new int(1);
感覺(jué)這個(gè)new完全沒(méi)必要啊。

而且Ptr<T>的值傳遞會(huì)很慢,完全沒(méi)有了指針的速度啊。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 05:41 | 陳梓瀚(vczh)
@SonicLing
我不會(huì)為了不是瓶頸部分的效率而讓開發(fā)效率大大下降的。加班的原因還不是因?yàn)槌绦驅(qū)懙寐?nbsp; 回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 05:42 | 陳梓瀚(vczh)
@SonicLing
這個(gè)new有必要,counter==1也是要有counter的。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 06:17 | SonicLing
@陳梓瀚(vczh)
我的意思是直接用int counter,而不是指針。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 17:48 | zuhd
@SonicLing


全文可以理解為一段共享內(nèi)存的故事

你顯然沒(méi)有理解這段話的意思  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-25 20:02 | 陳梓瀚(vczh)
@SonicLing
那一共有三個(gè)Ptr,其中一個(gè)死了,你不可能同時(shí)改了另外兩個(gè)的counter。謝謝。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-26 07:58 | SonicLing
@陳梓瀚(vczh)
恩,我理解錯(cuò)了。我寫過(guò)類似的指針,只不過(guò)把counter放在對(duì)象里,共享對(duì)象同時(shí)也共享了counter,這樣在傳遞和內(nèi)存分配方面效率高一點(diǎn),成員只包含一個(gè)指針,優(yōu)化收益也高一些,免去了過(guò)多的new/delete。因?yàn)楦阋粯樱苍趯懢幾g/解釋器,所以非常看重效率。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-26 08:10 | 陳梓瀚(vczh)
@SonicLing
T顯然是任意的,你不能修改。所以這才是我分出來(lái)的原因。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-26 08:10 | 陳梓瀚(vczh)
@SonicLing
虛擬機(jī)效率高就好了,編譯器沒(méi)必要。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-26 17:52 | 飯中淹
為什么不把pointer和counter放在一個(gè)結(jié)構(gòu)里,new這個(gè)結(jié)構(gòu)?
我做這個(gè)東西的時(shí)候,就是做這樣一個(gè)core_struct,然后加一個(gè)core_struct池來(lái)維護(hù)內(nèi)存。所有的Ptr傳遞和保存的就是這個(gè)core_struct的指針。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-06-26 21:02 | 陳梓瀚(vczh)
@飯中淹
你這種做法在遇到類型轉(zhuǎn)換的時(shí)候就有問(wèn)題了。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-07-01 00:32 |
使用type_traits模板技術(shù)可以非常漂亮的解決智能指針的子父類轉(zhuǎn)換問(wèn)題,如果要安全轉(zhuǎn)換子父類指針,根本辦法是打開RTTI,在智能指針實(shí)現(xiàn)的內(nèi)部使用dynamic_cast,并在出錯(cuò)時(shí)拋出異常。
但是RTTI我只建議在個(gè)別模塊中使用,這樣不會(huì)影響別的模塊的對(duì)象內(nèi)存結(jié)構(gòu),這種結(jié)構(gòu)會(huì)占用多余的內(nèi)存。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2010-07-01 01:06 | 陳梓瀚(vczh)
@釀
我這不就這么做嗎,請(qǐng)認(rèn)真閱讀。話說(shuō)回來(lái),RTTI在不是瓶頸的時(shí)候,我絕對(duì)不關(guān)掉它。  回復(fù)  更多評(píng)論
  
# re: C++實(shí)用技巧(三) 2014-10-30 00:15 | 大花貓
Ptr<T>& operator=(T* p)這個(gè)函數(shù)怎么沒(méi)有檢查自賦值  回復(fù)  更多評(píng)論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩在线一区二区| 国产精品自在在线| 欧美精品一区二区三区蜜臀| 国产乱人伦精品一区二区| 亚洲视频免费在线观看| 欧美国产日产韩国视频| 久久久亚洲国产天美传媒修理工| 国产精品久久九九| 亚洲免费视频观看| 亚洲午夜久久久久久久久电影院 | 亚洲自拍偷拍视频| 一区二区免费看| 欧美性色aⅴ视频一区日韩精品| 91久久精品日日躁夜夜躁国产| 欧美搞黄网站| 欧美精品一区二区三区久久久竹菊| 亚洲精品久久久久久久久久久久| 亚洲激精日韩激精欧美精品| 欧美高清hd18日本| 在线视频你懂得一区二区三区| 亚洲九九精品| 国产精品日韩欧美一区二区三区 | 欧美在线关看| 欧美伊人精品成人久久综合97| 国产欧美精品日韩精品| 久久女同互慰一区二区三区| 蜜桃av噜噜一区二区三区| 亚洲激情在线视频| 99精品国产一区二区青青牛奶| 国产精品大片| 久久亚洲综合| 欧美精品97| 欧美伊人久久久久久久久影院 | 欧美影视一区| 亚洲高清精品中出| 亚洲精品乱码视频| 国产欧美韩日| 亚洲娇小video精品| 国产精品二区影院| 久久视频国产精品免费视频在线| 亚洲精品一区在线观看| 久久精品日韩欧美| 亚洲欧美成人综合| 在线观看日韩精品| 日韩午夜在线观看视频| 国产精品一区二区三区观看| 久久久久亚洲综合| 欧美日韩妖精视频| 理论片一区二区在线| 欧美视频在线观看免费网址| 久久久久久一区二区| 欧美jizzhd精品欧美巨大免费| 亚洲永久免费av| 六月丁香综合| 午夜免费久久久久| 欧美精品一区二区三区蜜桃| 久久久久久久999精品视频| 欧美精品一区二区三区视频 | 亚洲国产mv| 国产日韩欧美一区二区| 亚洲二区在线视频| 国产一区二区电影在线观看| 91久久在线播放| 国产综合香蕉五月婷在线| 亚洲精品小视频在线观看| 国产一区二区在线免费观看| 亚洲精品综合精品自拍| 亚洲国产精品热久久| 午夜亚洲精品| 亚洲在线成人| 欧美紧缚bdsm在线视频| 免费h精品视频在线播放| 国产精品天美传媒入口| 最新成人在线| 影音先锋久久| 午夜精品在线观看| 亚洲女性喷水在线观看一区| 免费视频一区二区三区在线观看| 久久精品视频在线播放| 国产精品r级在线| 亚洲三级免费| 亚洲乱码久久| 欧美大香线蕉线伊人久久国产精品| 久久精精品视频| 国产精品激情电影| 亚洲最新视频在线| 一本色道久久综合精品竹菊 | 99国产精品久久| 亚洲靠逼com| 欧美1区3d| 亚洲国产99| 欧美少妇一区| 国模精品一区二区三区| 亚洲一区日韩在线| 欧美日韩亚洲国产一区| 99精品热视频只有精品10| 亚洲欧洲一区二区三区| 欧美成人激情在线| 亚洲国产精品ⅴa在线观看 | 久久婷婷麻豆| 午夜一级久久| 国产精品五月天| 亚洲欧美日韩一区二区三区在线| 亚洲欧美在线一区二区| 国产乱码精品一区二区三区不卡 | 欧美新色视频| 亚洲午夜激情网页| 亚洲乱码国产乱码精品精98午夜 | 牛人盗摄一区二区三区视频| 你懂的视频欧美| 亚洲国产日韩一区二区| 欧美aⅴ一区二区三区视频| 亚洲韩日在线| 中文一区二区| 国产伦精品一区二区三| 欧美怡红院视频| 欧美激情视频给我| 亚洲午夜av| 国产自产v一区二区三区c| 久久九九免费| 亚洲欧洲一二三| 亚洲综合另类| 韩国av一区二区三区在线观看| 久热精品视频在线观看一区| 亚洲精品久久久久| 欧美一区三区二区在线观看| 亚洲福利视频免费观看| 欧美猛交免费看| 欧美亚洲日本国产| 亚洲国产成人久久综合| 亚洲女性裸体视频| 亚洲高清视频一区| 国产精品视频成人| 久久亚洲综合色| 一级日韩一区在线观看| 老鸭窝毛片一区二区三区| 亚洲手机在线| 亚洲第一精品在线| 国产精品久久久久高潮| 久热精品视频| 亚洲欧美日韩在线| 91久久国产综合久久| 久久精品欧洲| 亚洲影院在线观看| 亚洲精品影院在线观看| 国产午夜精品一区二区三区欧美| 欧美成人免费网站| 久久丁香综合五月国产三级网站| 亚洲激情第一区| 久久在精品线影院精品国产| 亚洲视频在线视频| 亚洲黄色一区二区三区| 国产一区二区三区免费观看| 欧美日韩一区二区三区在线 | 亚洲人成在线免费观看| 国产日韩在线播放| 欧美特黄视频| 欧美成人综合在线| 久久精品九九| 午夜精品视频网站| 中文日韩欧美| 亚洲精品在线一区二区| 欧美www在线| 亚洲电影免费| 久久久欧美精品| 欧美一区二区三区另类| 一道本一区二区| 亚洲精品欧美激情| 亚洲第一精品电影| 欧美成年人网| 欧美不卡激情三级在线观看| 久久久人成影片一区二区三区| 午夜精品视频在线观看一区二区| 亚洲字幕在线观看| 亚洲自拍另类| 午夜精品久久久久久久99水蜜桃| 一区二区三区高清在线观看| 亚洲国产日韩在线| 亚洲欧洲美洲综合色网| 亚洲丁香婷深爱综合| 亚洲第一黄色| 亚洲日本成人网| 亚洲久久一区| 一区二区三区欧美成人| 亚洲午夜激情| 亚洲视频在线观看视频| 亚洲天天影视| 小黄鸭视频精品导航| 性欧美videos另类喷潮| 欧美一区日韩一区| 久久久久久午夜| 免费在线看一区| 欧美激情欧美狂野欧美精品| 亚洲激情av| 一区二区三区久久网| 午夜在线成人av| 日韩一级网站| 欧美一级淫片播放口| 久久久99国产精品免费| 免费看精品久久片|