CString轉char*的兩種方法討論

來源:互聯網
上載者:User

原文地址:http://topic.csdn.net/t/20050503/21/3982385.html

分析的很透徹!

LPCTSTR   與   GetBuffer(int   nMinBufLength)    
  這兩個函數提供了與標準C的相容轉換。在實際中使用頻率很高,但卻是最容易出錯的地方。這兩個函數實際上返回的都是指標,但它們有何區別呢?以及調用它們後,幕後是做了怎樣的處理過程呢?  
      (1)   LPCTSTR   它的執行過程其實很簡單,只是返回引用記憶體塊的串地址。   它是作為操作符重載提供的,  
              所以在代碼中有時可以隱式轉換,而有時卻需強制轉制。如:  
                      CString   str;  
                      const   char*   p   =   (LPCTSTR)str;  
                      //假設有這樣的一個函數,Test(const   char*   p);     你就可以這樣調用  
                      Test(str);//這裡會隱式轉換為LPCTSTR  
      (2)   GetBuffer(int   nMinBufLength)   它類似,也會返回一個指標,不過它有點差別,返回的是LPTSTR  
      (3)   這兩者到底有何不同呢?我想告訴大家,其本質上完全不一樣,一般說LPCTSTR轉換後只應該當常量使用,或者做函數的入參;而GetBuffer(...)取出指標後,可以通過這個指標來修改裡面的內容,或者做函數的入參。為什麼呢?也許經常有這樣的代碼:  
                  CString   str("abcd");  
                  char*   p   =   (char*)(const   char*)str;  
                  p[2]   =   'z';        
              其實,也許有這樣的代碼後,你的程式並沒有錯,而且程式也運行得挺好。但它卻是非常危險的。再看  
                  CString   str("abcd");  
                  CString   test   =   str;  
                  ....  
                  char*   p   =   (char*)(const   char*)str;  
                  p[2]   =   'z';        
                  strcpy(p,   "akfjaksjfakfakfakj");//這下完蛋了        
              你知道此時,test中的值是多少嗎?答案是"abzd".它也跟著改變了,這不是你所期望發生的。但為什麼會這樣呢?你稍微想想就會明白,前面說過,因為CString是指向引用塊的,str與test指向同一塊地方,當你p[2]='z'後,當然test也會隨著改變。所以用它做LPCTSTR做轉換後,你只能去讀這塊資料,千萬別去改變它的內容。  
               
              假如我想直接通過指標去修改資料的話,那怎樣辦呢?就是用GetBuffer(...).看下述代碼:  
                  CString   str("abcd");  
                  CString   test   =   str;  
                  ....  
                  char*   p   =   str.GetBuffer(20);  
                  p[2]   =   'z';     //       執行到此,現在test中值卻仍是"abcd"  
                  strcpy(p,   "akfjaksjfakfakfakj");       //         執行到此,現在test中值還是"abcd"  
              為什麼會這樣?其實GetBuffer(20)調用時,它實際上另外建立了一塊新內塊存,並分配20位元組長度的buffer,而原來的記憶體區塊引述計數也相應減1.     所以執行代碼後str與test是指向了兩塊不同的地方,所以相安無事。  
        (4)   不過這裡還有一點注意事項:就是str.GetBuffer(20)後,str的分配長度為20,即指標p它所指向的buffer只有20位元組長,給它賦值時,切不可超過,否則災難離你不遠了;如果指定長度小於原來串長度,如GetBuffer(1),實際上它會分配4個位元組長度(即原來串長度);另外,當調用GetBuffer(...)後並改變其內容,一定要記得調用ReleaseBuffer(),這個函數會根據串內容來更新引用記憶體塊的頭部資訊。  
        (5)   最後還有一注意事項,看下述代碼:  
              char*   p   =   NULL;  
              const   char*   q   =   NULL;  
              {  
                      CString   str   =   "abcd";  
                      q   =   (LPCTSTR)str;  
                      p   =   str.GetBuffer(20);  
                      AfxMessageBox(q);//   合法的  
                      strcpy(p,   "this   is   test");//合法的,  
              }  
              AfxMessageBox(q);//   非法的,可能完蛋  
              strcpy(p,   "this   is   test");//非法的,可能完蛋  
              這裡要說的就是,當返回這些指標後,   如果CString對象生命結束,這些指標也相應無效。  
  3   拷貝   &   賦值   &   "引用記憶體塊"   什麼時候釋放?  
   
      下面示範一段代碼執行過程  
        void   Test()  
        {  
            CString   str("abcd");//str指向一引用記憶體塊(引用記憶體塊的引用計數為1,  
                                                        長度為4,分配長度為4)  
            CString   a;//a指向一初始資料狀態,  
            a   =   str;     //a與str指向同一引用記憶體塊(引用記憶體塊的引用計數為2,  
                                      長度為4,分配長度為4)  
            CString   b(a);//a、b與str指向同一引用記憶體塊(引用記憶體塊的引用  
                                        計數為3,長度為4,分配長度為4)  
            {  
                  LPCTSTR   temp   =   (LPCTSTR)a;//temp指向引用記憶體塊的串首地址。  
                                                                      (引用記憶體塊的引用計數為3,長度為4,分配長度為4)  
                  CString   d   =   a;   //a、b、d與str指向同一引用記憶體塊(引用記憶體塊的引用計數為4,                                                                 長度為4,分配長度為4)  
                  b   =   "testa";   //這條語句實際是調用CString::operator=(CString&)函數。  
                                                b指向一新分配的引用記憶體塊。(新分配的引用記憶體塊的  
                                                引用計數為1,長度為5,分配長度為5)  
                                            //同時原引用記憶體區塊引述計數減1.   a、d與str仍指向原  
                                              引用記憶體塊(引用記憶體塊的引用計數為3,長度為4,分配長度為4)                                            
            }//由於d生命結束,調用解構函式,導至引用計數減1(引用記憶體  
                塊的引用計數為2,長度為4,分配長度為4)  
            LPTSTR   temp   =   a.GetBuffer(10);//此語句也會導致重新分配新記憶體塊。  
                                                                        temp指向新分配引用記憶體塊的串首地址(新  
                                                                        分配的引用記憶體塊的引用計數為1,長度  
                                                                        為0,分配長度為10)  
                                                                        //同時原引用記憶體區塊引述計數減1.   只有str仍  
                                                                            指向原引用記憶體塊(引用記憶體塊的引用計數為1,  
                                                                            長度為4,分配長度為4)                                              
            strcpy(temp,   "temp");     //a指向的引用記憶體塊的引用計數為1,長度為0,分配長度為10  
            a.ReleaseBuffer();//注意:a指向的引用記憶體塊的引用計數為1,長度為4,分配長度為10  
        }  
        //執行到此,所有的局部變數生命週期都已結束。對象str   a   b   各自調用自己的析構構  
        //函數,所指向的引用記憶體塊也相應減1  
        //注意,str   a   b   所分別指向的引用記憶體塊的計數均為0,這導致所分配的記憶體塊釋放  
          通過觀察上面執行過程,我們會發現CString雖然可以多個對象指向同一引用內塊存,但是它們在進行各種拷貝、賦值及改變串內容時,它的處理是很智能並且非常安全的,完全做到了互不干涉、互不影響。當然必須要求你的代碼使用正確恰當,特別是實際使用中會有更複雜的情況,如做函數參數、引用、及有時需儲存到CStringList當中,如果哪怕有一小塊地方使用不當,其結果也會導致發生不可預知的錯誤

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.