@Jie's Blog

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

  在使用MFC開發時,字符串類CString大概是使用最多的類之一,它使得對字符串的處理變得很方便。但是,在一些場合下,CString存在一些明顯的效率問題。

  如下面的代碼

    CString a;

    CString b 
= "Hello world!";

    INT n 
= b.GetLength();
        
    
for( INT i = 0; i < n; i++ )
    
{
        a 
+= b[i];
        a 
+= TEXT("\r\n");
    }
    


這段代碼將字符串b中的每個字符拼接到字符串a,並在後面插入0x0D 0x0A。

當b為"Hello, world!"這樣簡單的字串時,程序的執行起來尚無問題。但是若b的字串很長的時候,就會出現明顯的效率問題。我使用自己的計算機做了一系列測試,得出如下的結果

 字符串b的大小 執行時間
-------------─ 
  001k    0.01s
  010k    0.41s
  020k    1.68s
  040k    6.02s
  080k    33.56s
  100k    80.46s

  可以說,當b的大小超過20K時,已經會出現明顯的延遲,當超過40k,用戶就會難以忍受了。

  為甚麼會出現這樣的情況?我們會想到,當被拼接的字符串b越長,要複製和插入到字串a的字就越多,循環的次數就越多,導致時間的增加。但是這只是一個方面,更為重要的原因在於--

  CString的拼接操作符"+"看似簡單,卻要完成相當多的操作。首先會對CString對象(例子中字串a)的數據緩衝區進行重新分配,接著找到字串的結束位置,將要拼接的串複製到這個位置開始的緩衝區中。隨著拼接的進行,CString對象的字串隨之變長,這些操作所需要的時間開銷也會逐步增加。

  如何解決這個問題呢,可以考慮,如果字串a的數據緩衝區一開始就固定下來,那麼此後在每次拼接前就不必去重新分配了;同時,用一個指針來指向已有字串的結束位置,就不必去尋找這個位置了。因此,將程序改寫如下。

    CString a;
    PTCHAR    buf, p;

    CString b 
= "Hello, world!";
    INT n 
= b.GetLength();
    PTCHAR  q 
= b.GetBuffer(n);

    p 
= buf = (PTCHAR)malloc( sizeof(TCHAR) * (n*3+1) );

    
while*q )
    
{
        
*p++ = *q++;
        
*p++ = '\r';
        
*p++ = '\n';
    }


    
*= '\0';
    
    a 
= buf;
    free( buf );

  再次測試後的結果是

 字符串b的大小 執行時間
-------------─ 
  040k    0.01s
  100k    0.01s
  500k    0.06s

  效率的提昇是多麼明顯。

  題外話,這個例子的一個啟示是,當遇到程序執行出現延遲的情形,可以首先從程序本身找原因,想辦法替換掉那些效率不高的元操作。如果確認已經優化過了,還可以考慮其他的方法如多線程,來完成任務。
posted on 2004-11-09 17:12  Zhuang Jie  阅读(2498)  评论(0编辑  收藏  举报