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

面對現實,超越自己
逆水行舟,不進則退
posts - 269,comments - 32,trackbacks - 0
本文轉自:http://topic.csdn.net/t/20031208/15/2540422.html

關于CString總結

前言:串操作是編程中最常用也最基本的操作之一
 

     做為VC程序員,無論是菜鳥或高手都曾用過CString.而且好像實際編程中很難離得開它(雖然它不是標準C++中的庫).因為MFC中提供的這個類對我們操作字串實在太方便了,CString不僅提供各種豐富的操作函數、操作符重載,使我們使用起串起來更象basic中那樣直觀;而且它還提供了動態內存分配,使我們減少了多少字符串數組越界的隱患。但是,我們在使用過程中也體會到CString簡直太容易出錯了,而且有的不可捉摸。所以有許多高人站過來,建議拋棄它。
        在此,我個人認為:CString封裝得確實很完美,它有許多優點,如“容易使用   ,功能強,動態分配內存,大量進行拷貝時它很能節省內存資源并且執行效率高,與標準C完全兼容,同時支持多字節與寬字節,由于有異常機制所以使用它安全方便”   其實,使用過程中之所以容易出錯,那是因為我們對它了解得還不夠,特別是它的實現機制。因為我們中的大多數人,在工作中并不愛那么深入地去看關于它的文檔,何況它還是英文的。  
      由于前幾天我在工作中遇到了一個本不是問題但卻特別棘手、特別難解決而且莫名驚詫的問題。最后發現是由于CString引發的,后來,沒辦法,我把整個CString的實現全部看了一遍,才慌然大悟,并徹底弄清了問題的原因(這個問題,我已在csdn上開貼)。在此,我想把我的一些關于CString的知識總結一番,以供他(她)人借鑒,也許其中有我理解上的錯誤,望發現者能通知我,不勝感謝。

1   CString實現的機制 

      CString是通過“引用”來管理串的,“引用”這個詞我相信大家并不陌生,象Window內核對象、COM對象等都是通過引用來實現的。而CString也是通過這樣的機制來管理分配的內存塊。實際上CString對象只有一個指針成員變量,所以任何CString實例的長度只有4字節. 
      即:   int   len   =   sizeof(CString);//len等于4
     這個指針指向一個相關的引用內存塊,如圖:   CString   str( "abcd ");
                                                                                        ___
          ____________                                                     |       |  
        |                         |                                                   |       |  
        |   0x04040404   |                                                   |       |     head部,為引用內存塊相關信息
        |____________|                                                   |       |
                  str                                                               |___|
                                                                                      | 'a '|   0x40404040
                                                                                      | 'b '|
                                                                                      | 'c '|
                                                                                      | 'd '|
                                                                                      |   0   |

    正因為如此,一個這樣的內存塊可被多個CString所引用,例如下列代碼:
1 CString   str( "abcd "); 
2 CString   a   =   str; 
3 CString   b(str); 
4 CString   c; 
5 c   =   b; 
    上面代碼的結果是:上面四個對象(str,a,b,c)中的成員變量指針有相同的值,都為0x40404040.而這塊內存塊怎么知道有多少個CString引用它呢?同樣,它也會記錄一些信息。如被引用數,串長度,分配內存長度。
這塊引用內存塊的結構定義如下:
1 struct   CStringData 
2 
3     long   nRefs;               //表示有多少個CString   引用它.   4 
4     int   nDataLength;     //串實際長度.   4 
5     int   nAllocLength;   //總共分配的內存長度(不計這頭部的12字節).   4 
6 }; 
     由于有了這些信息,CString就能正確地分配、管理、釋放引用內存塊。
如果你想在調試程序的時候獲得這些信息。可以在Watch窗口鍵入下列表達式:
1 (CStringData*)((CStringData*)(this-> m_pchData)-1)或 
2 (CStringData*)((CStringData*)(str.m_pchData)-1)//str為指CString實例
    正因為采用了這樣的好機制,使得CString在大量拷貝時,不僅效率高,而且分配內存少。

2   LPCTSTR   與   GetBuffer(int   nMinBufLength) 
 
    這兩個函數提供了與標準C的兼容轉換。在實際中使用頻率很高,但卻是最容易出錯的地方。這兩個函數實際上返回的都是指針,但它們有何區別呢?以及調用它們后,幕后是做了怎樣的處理過程呢?
    (1)   LPCTSTR   它的執行過程其實很簡單,只是返回引用內存塊的串地址。   它是作為操作符重載提供的,
            所以在代碼中有時可以隱式轉換,而有時卻需強制轉制。如:
1                     CString   str; 
2                     const   char*   p   =   (LPCTSTR)str; 
3                     //假設有這樣的一個函數,Test(const   char*   p);     你就可以這樣調用 
4                     Test(str);//這里會隱式轉換為LPCTSTR 
    (2)   GetBuffer(int   nMinBufLength)   它類似,也會返回一個指針,不過它有點差別,返回的是LPTSTR
    (3)   這兩者到底有何不同呢?我想告訴大家,其本質上完全不一樣,一般說LPCTSTR轉換后只應該當常量使用,或者做函數的入參;而GetBuffer(...)取出指針后,可以通過這個指針來修改里面的內容,或者做函數的入參。為什么呢?也許經常有這樣的代碼: 
      
1   CString   str( "abcd "); 
2                 char*   p   =   (char*)(const   char*)str; 
3                 p[2]   =   '';       
    其實,也許有這樣的代碼后,你的程序并沒有錯,而且程序也運行得挺好。但它卻是非常危險的。再看 
      
1 CString   str( "abcd "); 
2                 CString   test   =   str; 
3                 
4                 char*   p   =   (char*)(const   char*)str; 
5                 p[2]   =   '';       
6                 strcpy(p,   "akfjaksjfakfakfakj ");//這下完蛋了      
           
    你知道此時,test中的值是多少嗎?答案是 "abzd ".它也跟著改變了,這不是你所期望發生的。但為什么會這樣呢?你稍微想想就會明白,前面說過,因為CString是指向引用塊的,str與test指向同一塊地方,當你p[2]= 'z '后,當然test也會隨著改變。所以用它做LPCTSTR做轉換后,你只能去讀這塊數據,千萬別去改變它的內容。 
            
    假如我想直接通過指針去修改數據的話,那怎樣辦呢?就是用GetBuffer(...).看下述代碼: 
 
1   CString   str( "abcd "); 
2                 CString   test   =   str; 
3                 
4                 char*   p   =   str.GetBuffer(20); 
5                 p[2]   =   '';     //       執行到此,現在test中值卻仍是 "abcd " 
6                 strcpy(p,   "akfjaksjfakfakfakj ");       //         執行到此,現在test中值還是 "abcd " 
7 
    為什么會這樣?其實GetBuffer(20)調用時,它實際上另外建立了一塊新內塊存,并分配20字節長度的buffer,而原來的內存塊引用計數也相應減1.     所以執行代碼后str與test是指向了兩塊不同的地方,所以相安無事。

    (4)   不過這里還有一點注意事項:就是str.GetBuffer(20)后,str的分配長度為20,即指針p它所指向的buffer只有20字節長,給它賦值時,切不可超過,否則災難離你不遠了;如果指定長度小于原來串長度,如GetBuffer(1),實際上它會分配4個字節長度(即原來串長度);另外,當調用GetBuffer(...)后并改變其內容,一定要記得調用ReleaseBuffer(),這個函數會根據串內容來更新引用內存塊的頭部信息。 
    (5)   最后還有一注意事項,看下述代碼: 
 1  char*   p   =   NULL; 
 2             const   char*   q   =   NULL; 
 3             { 
 4                     CString   str   =   "abcd "
 5                     q   =   (LPCTSTR)str; 
 6                     p   =   str.GetBuffer(20); 
 7                     AfxMessageBox(q);//   合法的 
 8                     strcpy(p,   "this   is   test ");//合法的, 
 9             } 
10             AfxMessageBox(q);//   非法的,可能完蛋 
11             strcpy(p,   "this   is   test ");//非法的,可能完蛋 
    這里要說的就是,當返回這些指針后,   如果CString對象生命結束,這些指針也相應無效。 
    下面演示一段代碼執行過程          
 1   void   Test() 
 2       { 
 3           CString   str( "abcd ");//str指向一引用內存塊(引用內存塊的引用計數為1, 
 4                                                       長度為4,分配長度為4) 
 5           CString   a;//a指向一初始數據狀態, 
 6           a   =   str;     //a與str指向同一引用內存塊(引用內存塊的引用計數為2, 
 7                                     長度為4,分配長度為4) 
 8           CString   b(a);//a、b與str指向同一引用內存塊(引用內存塊的引用 
 9                                       計數為3,長度為4,分配長度為4) 
10           { 
11                 LPCTSTR   temp   =   (LPCTSTR)a;//temp指向引用內存塊的串首地址。 
12                                                                     (引用內存塊的引用計數為3,長度為4,分配長度為4) 
13                 CString   d   =   a;   //a、b、d與str指向同一引用內存塊(引用內存塊的引用計數為4,                                                                 長度為4,分配長度為4) 
14                 b   =   "testa ";   //這條語句實際是調用CString::operator=(CString&)函數。 
15                                               b指向一新分配的引用內存塊。(新分配的引用內存塊的 
16                                               引用計數為1,長度為5,分配長度為5) 
17                                           //同時原引用內存塊引用計數減1.   a、d與str仍指向原 
18                                             引用內存塊(引用內存塊的引用計數為3,長度為4,分配長度為4)                                           
19           }//由于d生命結束,調用析構函數,導至引用計數減1(引用內存 
20               塊的引用計數為2,長度為4,分配長度為4) 
21           LPTSTR   temp   =   a.GetBuffer(10);//此語句也會導致重新分配新內存塊。 
22                                                                       temp指向新分配引用內存塊的串首地址(新 
23                                                                       分配的引用內存塊的引用計數為1,長度 
24                                                                       為0,分配長度為10) 
25                                                                       //同時原引用內存塊引用計數減1.   只有str仍 
26                                                                           指向原引用內存塊(引用內存塊的引用計數為1, 
27                                                                           長度為4,分配長度為4)                                             
28           strcpy(temp,   "temp ");     //a指向的引用內存塊的引用計數為1,長度為0,分配長度為10 
29           a.ReleaseBuffer();//注意:a指向的引用內存塊的引用計數為1,長度為4,分配長度為10 
30       } 
31       //執行到此,所有的局部變量生命周期都已結束。對象str   a   b   各自調用自己的析構構 
32       //函數,所指向的引用內存塊也相應減1 
33       //注意,str   a   b   所分別指向的引用內存塊的計數均為0,這導致所分配的內存塊釋放 

     通過觀察上面執行過程,我們會發現CString雖然可以多個對象指向同一引用內塊存,但是它們在進行各種拷貝、賦值及改變串內容時,它的處理是很智能并且非常安全的,完全做到了互不干涉、互不影響。當然必須要求你的代碼使用正確恰當,特別是實際使用中會有更復雜的情況,如做函數參數、引用、及有時需保存到CStringList當中,如果哪怕有一小塊地方使用不當,其結果也會導致發生不可預知的錯誤 

3     FreeExtra()的作用

     看這段代碼 
1 CString   str( "test "); 
2 LPTSTR   temp   =   str.GetBuffer(50); 
3 strcpy(temp,   "there   are   22   character "); 
4 str.ReleaseBuffer(); 
5 str.FreeExtra(); 

     上面代碼執行到第(4)行時,大家都知道str指向的引用內存塊計數為1,長度為22,分配長度為50.   那么執行str.FreeExtra()時,它會釋放所分配的多余的內存。(引用內存塊計數為1,長度為22,分配長度為22) 

4     Format(...)     與   FormatV(...) 

     這條語句在使用中是最容易出錯的。因為它最富有技巧性,也相當靈活。在這里,我沒打算對它細細分析,實際上sprintf(...)怎么用,它就怎么用。我只提醒使用時需注意一點:就是它的參數的特殊性,由于編譯器在編譯時并不能去校驗格式串參數與對應的變元的類型及長度。所以你必須要注意,兩者一定要對應上, 
     否則就會出錯。如:
1  CString   str; 
2       int   a   =   12
3       str.Format( "first:%l,   second:   %s ",   a,   "error ");//result?試試
 
5     LockBuffer()   與   UnlockBuffer()
 

      顧名思議,這兩個函數的作用就是對引用內存塊進行加鎖及解鎖。
      但使用它有什么作用及執行過它后對CString串有什么實質上的影響。其實挺簡單,看下面代碼:
1 CString   str( "test "); 
2 str.LockBuffer(); 
3 CString   temp   =   str; 
4 str.UnlockBuffer(); 
5 str.LockBuffer(); 
6 str   =   "error "
7 str.ReleaseBuffer(); 
8 
      執行完(3)后,與通常情況下不同,temp與str并不指向同一引用內存塊。你可以在watch窗口用這個表達式(CStringData*)((CStringData*)(str.m_pchData)-1)看看。
      其實在msdn中有說明: 
       While   in   a   locked   state,   the   string   is   protected   in   two   ways:   
       No   other   string   can   get   a   reference   to   the   data   in   the   locked   string,   even   if   that   string   is   assigned   to   the   locked   string. 
       The   locked   string   will   never   reference   another   string,   even   if   that   other   string   is   copied   to   the   locked   string.   

6     CString   只是處理串嗎?
 
     不對,CString不只是能操作串,而且還能處理內存塊數據。功能完善吧!看這段代碼
1 char     p[20]; 
2 for(int   loop=0;   loop <sizeof(p);   loop++
3 
4 p[loop]   =   10-loop; 
5 
6 CString   str((LPCTSTR)p,   20); 
7 char   temp[20]; 
8 memcpy(temp,   str,   str.GetLength()); 
      str完全能夠轉載內存塊p到內存塊temp中。所以能用CString來處理二進制數據 

7     AllocSysString()與SetSysString(BSTR*)  
 
      這兩個函數提供了串與BSTR的轉換。使用時須注意一點:當調用AllocSysString()后,須調用它SysFreeString(...)   

8     參數的安全檢驗 

      在MFC中提供了多個宏來進行參數的安全檢查,如:ASSERT.     其中在CString中也不例外,有許多這樣的參數檢驗,其實這也說明了代碼的安全性高,可有時我們會發現這很煩,也導致Debug與Release版本不一樣,如有時程序Debug通正常,而Release則程序崩潰;而有時恰相反,Debug不行,Release行。其實我個人認為,我們對CString的使用過程中,應力求代碼質量高,不能在Debug版本中出現任何斷言框,哪怕release運行似乎看起來一切正常。但很不安全。如下代碼:
 
1 CString   str( "test "); 
2 str.LockBuffer(); 
3 LPTSTR   temp   =   str.GetBuffer(10); 
4 strcpy(temp,   "error "); 
5 str.ReleaseBuffer(); 
6 str.ReleaseBuffer();//執行到此時,Debug版本會彈出錯框
    
9   CString的異常處理 

      我只想強調一點:只有分配內存時,才有可能導致拋出CMemoryException.
      同樣,在msdn中的函數聲明中,注有throw(   CMemoryException)的函數都有重新分配或調整內存的可能。
 
10   跨模塊時的CString

    即一個DLL的接口函數中的參數為CString&時,它會發生怎樣的現象。解答我遇到的 
    問題。我的問題原來已經發貼,地址為:http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136 

    構造一個這樣CString對象時,如CString   str,你可知道此時的str所指向的引用內存塊嗎?也許你會認為它指向NULL。其實不對,如果這樣的話,CString所采用的引用機制管理內存塊就會有麻煩了,所以CString在構造一個空串的對象時,它會指向一個固定的初始化地址,這塊數據的聲明如下:
      AFX_STATIC_DATA   int   _afxInitData[]   =   {-1,0,0,0};
    簡要描述概括一下:當某個CString對象串置空的話,如Empty(),CString   a等,它的成員變量m_pchData就會指向_afxInitData這個變量的地址。當這個CString對象生命周期結束時,正常情況下它會去對所指向的引用內存塊計數減1,如果引用計數為0(即沒有任何CString引用時),則釋放這塊引用內存。而現在的情況是如果CString所指向的引用內存塊是初始化內存塊時,則不會釋放任何內存。

    說了這么多,這與我遇到的問題有什么關系呢?其實關系大著呢?其真正原因就是如果exe模塊與dll模塊有一
    個是static編譯連接的話。那么這個CString初始化數據在exe模塊與dll模塊中有不同的地址,因為static連接則會在本模塊中有一份源代碼的拷貝。另外一種情況,如果兩個模塊都是share連接的,CString的實現代碼則在另一個單獨的dll實現,而AFX_STATIC_DATA指定變量只裝一次,所以兩個模塊中_afxInitData有相同的地址。 
    現在問題完全明白了吧!你可以自己去演示一下。 
 
1     __declspec   (dllexport)   void   test(CString&   str) 
2     { 
3         str   =   "abdefakdfj ";//如果是static連接,并且傳入的str為空串的話,這里出錯。 
4     }
 
    最后一點想法:寫得這里,其實CString中還有許多技巧性的好東東,我并沒去解釋。如很多重載的操作符、查找等。我認為還是詳細看看msdn,這樣會比我講好多了。我只側重那些情況下會可能出錯。當然,我敘述如有錯誤,敬請高手指點,不勝感謝!

sorry,改正一下 
     看起來一切正常。但很不安全。如下代碼:  
1 CString   str( "test "); 
2 str.LockBuffer(); 
3 LPTSTR   temp   =   str.GetBuffer(10); 
4 strcpy(temp,   "error "); 
5 str.ReleaseBuffer(); 
6 str.UnlockBuffer();//執行到此時,Debug版本會彈出錯框 
posted on 2012-04-28 09:53 王海光 閱讀(498) 評論(0)  編輯 收藏 引用 所屬分類: MFC
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精品免费电影| 国产综合视频在线观看| 欧美一区二区精美| 一本综合精品| 亚洲一区二区三区在线| 午夜精品久久久久久久蜜桃app| 亚洲精品美女在线| 最新日韩中文字幕| 亚洲小说欧美另类社区| 亚洲综合久久久久| 久久久久久9| 欧美国产大片| 国产精品亚洲综合天堂夜夜 | 亚洲婷婷国产精品电影人久久| 亚洲美女毛片| 亚洲一区二区三区免费在线观看| 亚洲一区二区在线观看视频| 久久精品国产免费看久久精品| 久久一区亚洲| 国产精品久久97| 亚洲福利一区| 亚洲一二区在线| 欧美一区视频| 亚洲黄色视屏| 欧美在线free| 欧美日韩成人免费| 国内精品久久久久久| 99在线视频精品| 美女久久一区| 亚洲免费中文| 欧美日韩国产小视频| 伊人色综合久久天天五月婷| 亚洲天堂成人在线视频| 欧美**人妖| 午夜一区二区三区在线观看| 欧美激情区在线播放| 国产亚洲欧美一级| 亚洲主播在线观看| 亚洲激情第一页| 久久久噜噜噜久久中文字免| 久久精品99无色码中文字幕| 99视频精品全国免费| 久久国产精品高清| 日韩视频一区二区三区在线播放 | 免费成年人欧美视频| 亚洲一区三区视频在线观看| 欧美精品亚洲二区| 经典三级久久| 欧美一区免费视频| 亚洲视频在线免费观看| 欧美日韩国产美| 亚洲靠逼com| 欧美国产日韩a欧美在线观看| 欧美在线你懂的| 国产日韩在线播放| 久久成人一区| 亚洲欧美久久久| 国产精品影视天天线| 亚洲欧美韩国| 一本久久综合亚洲鲁鲁| 欧美午夜视频在线观看| 亚洲午夜小视频| 日韩视频永久免费观看| 欧美日韩国产bt| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 国产亚洲欧美日韩日本| 亚洲在线中文字幕| 亚洲午夜视频在线| 国产日本欧洲亚洲| 久久亚洲一区二区三区四区| 久久狠狠婷婷| 亚洲电影成人| 最新69国产成人精品视频免费| 男女视频一区二区| 99国产麻豆精品| 宅男噜噜噜66一区二区66| 国产精品扒开腿爽爽爽视频 | 久久天堂av综合合色| 在线播放日韩欧美| 亚洲高清在线观看| 欧美日本中文字幕| 欧美伊久线香蕉线新在线| 久久精品国产综合精品| 亚洲国产一区二区三区在线播| 亚洲国产婷婷综合在线精品| 欧美日韩高清区| 欧美在线观看你懂的| 久热精品在线视频| 久久久久久国产精品一区| 久久er精品视频| 国产字幕视频一区二区| 美女网站久久| 欧美成人精品在线观看| 亚洲午夜女主播在线直播| 亚洲欧美色婷婷| 亚洲二区视频在线| 日韩视频―中文字幕| 国产一区二区三区在线播放免费观看| 欧美.www| 国产精品视频| 欧美国产先锋| 国产精品久久久久久久久久久久久久 | 亚洲一区综合| 久久精品最新地址| 亚洲在线第一页| 免费中文字幕日韩欧美| 亚洲综合二区| 欧美精品18+| 久久久久久噜噜噜久久久精品| 欧美伦理在线观看| 欧美电影电视剧在线观看| 国产精品家教| 亚洲国产天堂久久综合| 国产一区二区三区在线免费观看| 日韩天堂在线观看| 亚洲精品美女在线观看| 久久国产一区二区三区| 亚洲女ⅴideoshd黑人| 欧美顶级少妇做爰| 欧美不卡在线| 在线观看日韩精品| 久久国产精品亚洲77777| 亚洲影院污污.| 欧美日本精品一区二区三区| 欧美成人在线免费视频| 精品动漫3d一区二区三区免费版| 亚洲婷婷免费| 香蕉成人啪国产精品视频综合网| 美日韩丰满少妇在线观看| 久久精品主播| 国产综合色精品一区二区三区| 亚洲尤物精选| 亚洲欧美在线磁力| 国产精品每日更新| 中日韩美女免费视频网址在线观看| 亚洲免费观看高清完整版在线观看| 久久综合五月| 亚洲国产成人av好男人在线观看| 国内揄拍国内精品少妇国语| 亚洲欧美日韩国产中文| 午夜精品在线| 国产日产精品一区二区三区四区的观看方式 | 久久精品女人的天堂av| 久久精品亚洲一区二区| 国产在线拍偷自揄拍精品| 午夜久久美女| 久久久久网站| 伊人狠狠色j香婷婷综合| 国产精品日韩一区二区| 美女免费视频一区| 亚洲国产精品毛片| 欧美黄色aa电影| 日韩午夜电影| 欧美一区二区三区四区高清| 国产伦精品一区| 久久国产精品99精品国产| 老司机免费视频久久| 亚洲电影一级黄| 欧美日韩国产色综合一二三四| 一区二区三区高清在线| 欧美一级午夜免费电影| 影音先锋久久精品| 欧美伦理视频网站| 亚洲男人的天堂在线aⅴ视频| 久久精品亚洲| 亚洲欧洲一区二区天堂久久| 欧美三级视频| 久久成人久久爱| 牛夜精品久久久久久久99黑人| 亚洲区一区二| 国产美女精品免费电影| 久久精品国产精品亚洲综合| 亚洲日本成人| 久久精品国产一区二区三| 亚洲精品乱码| 国产日韩欧美一区二区三区在线观看 | 欧美影院在线| 雨宫琴音一区二区在线| 欧美日韩黄色大片| 欧美自拍偷拍午夜视频| 亚洲美女av电影| 蜜月aⅴ免费一区二区三区 | 蜜桃av噜噜一区二区三区| 国产精品99久久不卡二区| 国产欧美日韩综合精品二区| 免费看亚洲片| 亚洲一二三区视频在线观看| 欧美国产免费| 久久精品国产96久久久香蕉| 亚洲视频综合在线| 亚洲三级免费观看| 国产手机视频精品| 欧美日韩一区在线观看视频| 久久综合色天天久久综合图片| 亚洲一级影院| 一本一本久久| 亚洲精品在线看| 美乳少妇欧美精品| 久久福利一区| 午夜精品久久久久久99热软件 |