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

road420

導(dǎo)航

<2025年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

統(tǒng)計

常用鏈接

留言簿(2)

隨筆檔案

文章檔案

搜索

最新評論

閱讀排行榜

評論排行榜

CString

1. CString實現(xiàn)的機(jī)制.

CString是通過“引用”來管理串的,“引用”這個詞我相信大家并不陌生,象Window內(nèi)核對象、COM對象等都是通過引用來實現(xiàn)的。而CString也是通過這樣的機(jī)制來管理分配的內(nèi)存塊。實際上CString對象只有一個指針成員變量,所以任何CString實例的長度只有4字節(jié).

即: int len = sizeof(CString);//len等于4

這個指針指向一個相關(guān)的引用內(nèi)存塊,如圖: CString str("abcd");

‘A’

‘B’

‘C’

‘D’

0

0x04040404 head部,為引用內(nèi)存塊相關(guān)信息

str 0x40404040

正因為如此,一個這樣的內(nèi)存塊可被多個CString所引用,例如下列代碼:

CString str("abcd");

CString a = str;

CString b(str);

CString c;

c = b;

上面代碼的結(jié)果是:上面四個對象(str,a,b,c)中的成員變量指針有相同的值,都為0x40404040.而這塊內(nèi)存塊怎么知道有多少個CString引用它呢?同樣,它也會記錄一些信息。如被引用數(shù),串長度,分配內(nèi)存長度。

這塊引用內(nèi)存塊的結(jié)構(gòu)定義如下:

struct CStringData

{

long nRefs; //表示有多少個CString 引用它. 4

int nDataLength; //串實際長度. 4

int nAllocLength; //總共分配的內(nèi)存長度(不計這頭部的12字節(jié)). 4

};

由于有了這些信息,CString就能正確地分配、管理、釋放引用內(nèi)存塊。

如果你想在調(diào)試程序的時候獲得這些信息。可以在Watch窗口鍵入下列表達(dá)式:

(CStringData*)((CStringData*)(this->m_pchData)-1)或

(CStringData*)((CStringData*)(str.m_pchData)-1)//str為指CString實例

正因為采用了這樣的好機(jī)制,使得CString在大量拷貝時,不僅效率高,而且分配內(nèi)存少。

2.LPCTSTR 與 GetBuffer(int nMinBufLength)

這兩個函數(shù)提供了與標(biāo)準(zhǔn)C的兼容轉(zhuǎn)換。在實際中使用頻率很高,但卻是最容易出錯的地方。這兩個函數(shù)實際上返回的都是指針,但它們有何區(qū)別呢?以及調(diào)用它們后,幕后是做了怎樣的處理過程呢?

(1) LPCTSTR 它的執(zhí)行過程其實很簡單,只是返回引用內(nèi)存塊的串地址。 它是作為操作符重載提供的,所以在代碼中有時可以隱式轉(zhuǎn)換,而有時卻需強(qiáng)制轉(zhuǎn)制。如:

CString str;

const char* p = (LPCTSTR)str;

//假設(shè)有這樣的一個函數(shù),Test(const char* p); 你就可以這樣調(diào)用

Test(str);//這里會隱式轉(zhuǎn)換為LPCTSTR

(2) GetBuffer(int nMinBufLength) 它類似,也會返回一個指針,不過它有點差別,返回的是LPTSTR

(3) 這兩者到底有何不同呢?我想告訴大家,其本質(zhì)上完全不一樣,一般說LPCTSTR轉(zhuǎn)換后只應(yīng)該當(dāng)常量使用,或者做函數(shù)的入?yún)ⅲ欢鳪etBuffer(...)取出指針后,可以通過這個指針來修改里面的內(nèi)容,或者做函數(shù)的出參。為什么呢?也許經(jīng)常有這樣的代碼:

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"。它也跟著改變了,這不是你所期望發(fā)生的。但為什么會這樣呢?你稍微想想就會明白,前面說過,因為CString是指向引用塊的,str與test指向同一塊地方,當(dāng)你p[2]='z'后,當(dāng)然test也會隨著改變。所以用它做LPCTSTR做轉(zhuǎn)換后,你只能去讀這塊數(shù)據(jù),千萬別去改變它的內(nèi)容。

假如我想直接通過指針去修改數(shù)據(jù)的話,那怎樣辦呢?就是用GetBuffer(...).看下述代碼:

CString str("abcd");

CString test = str;

....

char* p = str.GetBuffer(20);

p[2] = 'z'; // 執(zhí)行到此,現(xiàn)在test中值卻仍是"abcd"

strcpy(p, "akfjaksjfakfakfakj"); // 執(zhí)行到此,現(xiàn)在test中值還是"abcd"

為什么會這樣?其實GetBuffer(20)調(diào)用時,它實際上另外建立了一塊新內(nèi)塊存,并分配20字節(jié)長度的buffer,而原來的內(nèi)存塊引用計數(shù)也相應(yīng)減1. 所以執(zhí)行代碼后str與test是指向了兩塊不同的地方,所以相安無事。

(4) 不過這里還有一點注意事項:就是str.GetBuffer(20)后,str的分配長度為20,即指針p它所指向的buffer只有20字節(jié)長,給它賦值時,切不可超過,否則災(zāi)難離你不遠(yuǎn)了;如果指定長度小于原來串長度,如GetBuffer(1),實際上它會分配4個字節(jié)長度(即原來串長度);另外,當(dāng)調(diào)用GetBuffer(...)后并改變其內(nèi)容,一定要記得調(diào)用ReleaseBuffer(),這個函數(shù)會根據(jù)串內(nèi)容來更新引用內(nèi)存塊的頭部信息。

(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");//非法的,可能完蛋

這里要說的就是,當(dāng)返回這些指針后, 如果CString對象生命結(jié)束,這些指針也相應(yīng)無效。

3.拷貝 & 賦值 & "引用內(nèi)存塊" 什么時候釋放?

下面演示一段代碼執(zhí)行過程

void Test()

{

CString str("abcd");

//str指向一引用內(nèi)存塊(引用內(nèi)存塊的引用計數(shù)為1,長度為4,分配長度為4)

CString a;

//a指向一初始數(shù)據(jù)狀態(tài),

a = str;

//a與str指向同一引用內(nèi)存塊(引用內(nèi)存塊的引用計數(shù)為2,長度為4,分配長度為4)

CString b(a);

//a、b與str指向同一引用內(nèi)存塊(引用內(nèi)存塊的引用計數(shù)為3,長度為4,分配長度為4)

{

LPCTSTR temp = (LPCTSTR)a;

//temp指向引用內(nèi)存塊的串首地址。(引用內(nèi)存塊的引用計數(shù)為3,長度為4,分配長度為4)

CString d = a;

//a、b、d與str指向同一引用內(nèi)存塊(引用內(nèi)存塊的引用計數(shù)為4, 長度為4,分配長度為4)

b = "testa";

//這條語句實際是調(diào)用CString::operator=(CString&)函數(shù)。 b指向一新分配的引用內(nèi)存塊。(新分配的引用內(nèi)存塊的 引用計數(shù)為1, 長度為5, 分配長度為5)

//同時原引用內(nèi)存塊引用計數(shù)減1. a、d與str仍指向原 引用內(nèi)存塊(引用內(nèi)存塊的引用計數(shù)為3,長度為4,分配長度為4)

}

//由于d生命結(jié)束,調(diào)用析構(gòu)函數(shù),導(dǎo)至引用計數(shù)減1(引用內(nèi)存塊的引用計數(shù)為2,長度為4,分配長度為4)

LPTSTR temp = a.GetBuffer(10);

//此語句也會導(dǎo)致重新分配新內(nèi)存塊。temp指向新分配引用內(nèi)存塊的串首地址(新 分配的引用內(nèi)存塊的引用計數(shù)為1,長度為0,分配長度為10)

//同時原引用內(nèi)存塊引用計數(shù)減1. 只有str仍 指向原引用內(nèi)存塊 (引用內(nèi)存塊的引用計數(shù)為1, 長度為4, 分配長度為4)

strcpy(temp, "temp");

//a指向的引用內(nèi)存塊的引用計數(shù)為1,長度為0,分配長度為10 a.ReleaseBuffer();//注意:a指向的引用內(nèi)存塊的引用計數(shù)為1,長度為4,分配長度為10

}

//執(zhí)行到此,所有的局部變量生命周期都已結(jié)束。對象str a b 各自調(diào)用自己的析構(gòu)構(gòu)

//函數(shù),所指向的引用內(nèi)存塊也相應(yīng)減1

//注意,str a b 所分別指向的引用內(nèi)存塊的計數(shù)均為0,這導(dǎo)致所分配的內(nèi)存塊釋放

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

5 FreeExtra()的作用

看這段代碼

(1) CString str("test");

(2) LPTSTR temp = str.GetBuffer(50);

(3) strcpy(temp, "there are 22 character");

(4) str.ReleaseBuffer();

(5) str.FreeExtra();

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

6 Format(...) 與 FormatV(...)

這條語句在使用中是最容易出錯的。因為它最富有技巧性,也相當(dāng)靈活。在這里,我沒打算對它細(xì)細(xì)分析,實際上sprintf(...)怎么用,它就怎么用。我只提醒使用時需注意一點:就是它的參數(shù)的特殊性,由于編譯器在編譯時并不能去校驗格式串參數(shù)與對應(yīng)的變元的類型及長度。所以你必須要注意,兩者一定要對應(yīng)上,

否則就會出錯。如:

CString str;

int a = 12;

str.Format("first:%l, second: %s", a, "error");//result?試試

7 LockBuffer() 與 UnlockBuffer()

顧名思議,這兩個函數(shù)的作用就是對引用內(nèi)存塊進(jìn)行加鎖及解鎖。但使用它有什么作用及執(zhí)行過它后對CString串有什么實質(zhì)上的影響。其實挺簡單,看下面代碼:

(1) CString str("test");

(2) str.LockBuffer();

(3) CString temp = str;

(4) str.UnlockBuffer();

(5) str.LockBuffer();

(6) str = "error";

(7) str.ReleaseBuffer();

執(zhí)行完(3)后,與通常情況下不同,temp與str并不指向同一引用內(nèi)存塊。你可以在watch窗口用這個表達(dá)式(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.

8 CString 只是處理串嗎?

不對,CString不只是能操作串,而且還能處理內(nèi)存塊數(shù)據(jù)。功能完善吧!看這段代碼

char p[20];

for(int loop=0; loop<sizeof(p); loop++)

{

p[loop] = 10-loop;

}

CString str((LPCTSTR)p, 20);

char temp[20];

memcpy(temp, str, str.GetLength());

str完全能夠轉(zhuǎn)載內(nèi)存塊p到內(nèi)存塊temp中。所以能用CString來處理二進(jìn)制數(shù)據(jù)

8 AllocSysString()與SetSysString(BSTR*)

這兩個函數(shù)提供了串與BSTR的轉(zhuǎn)換。使用時須注意一點:當(dāng)調(diào)用AllocSysString()后,須調(diào)用它SysFreeString(...)

9 參數(shù)的安全檢驗

在MFC中提供了多個宏來進(jìn)行參數(shù)的安全檢查,如:ASSERT. 其中在CString中也不例外,有許多這樣的參數(shù)檢驗,其實這也說明了代碼的安全性高,可有時我們會發(fā)現(xiàn)這很煩,也導(dǎo)致Debug與Release版本不一樣,如有時程序Debug通正常,而Release則程序崩潰;而有時恰相反,Debug不行,Release行。其實我個人認(rèn)為,我們對CString的使用過程中,應(yīng)力求代碼質(zhì)量高,不能在Debug版本中出現(xiàn)任何斷言框,哪怕release運行似乎看起來一切正常。但很不安全。如下代碼:

(1) CString str("test");

(2) str.LockBuffer();

(3) LPTSTR temp = str.GetBuffer(10);

(4) strcpy(temp, "error");

(5) str.ReleaseBuffer();

(6) str.ReleaseBuffer();//執(zhí)行到此時,Debug版本會彈出錯框

10 CString的異常處理

我只想強(qiáng)調(diào)一點:只有分配內(nèi)存時,才有可能導(dǎo)致拋出CMemoryException.

同樣,在msdn中的函數(shù)聲明中,注有throw( CMemoryException)的函數(shù)都有重新分配或調(diào)整內(nèi)存的可能。

11 跨模塊時的Cstring。即一個DLL的接口函數(shù)中的參數(shù)為CString&時,它會發(fā)生怎樣的現(xiàn)象。解答我遇到的問題。我的問題原來已經(jīng)發(fā)貼,地址為:

http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136

構(gòu)造一個這樣CString對象時,如CString str,你可知道此時的str所指向的引用內(nèi)存塊嗎?也許你會認(rèn)為它指向NULL。其實不對,如果這樣的話,CString所采用的引用機(jī)制管理內(nèi)存塊就會有麻煩了,所以CString在構(gòu)造一個空串的對象時,它會指向一個固定的初始化地址,這塊數(shù)據(jù)的聲明如下:

AFX_STATIC_DATA int _afxInitData[] = {-1,0,0,0};

簡要描述概括一下:當(dāng)某個CString對象串置空的話,如Empty(),CString a等,它的成員變量m_pchData就會指向_afxInitData這個變量的地址。當(dāng)這個CString對象生命周期結(jié)束時,正常情況下它會去對所指向的引用內(nèi)存塊計數(shù)減1,如果引用計數(shù)為0(即沒有任何CString引用它時),則釋放這塊引用內(nèi)存。而現(xiàn)在的情況是如果CString所指向的引用內(nèi)存塊是初始化內(nèi)存塊時,則不會釋放任何內(nèi)存。

說了這么多,這與我遇到的問題有什么關(guān)系呢?其實關(guān)系大著呢?其真正原因就是如果exe模塊與dll模塊有一個是static編譯連接的話。那么這個CString初始化數(shù)據(jù)在exe模塊與dll模塊中有不同的地址,因為static連接則會在本模塊中有一份源代碼的拷貝。另外一種情況,如果兩個模塊都是share連接的,CString的實現(xiàn)代碼則在另一個單獨的dll中實現(xiàn),而AFX_STATIC_DATA指定變量只裝一次,所以兩個模塊中_afxInitData有相同的地址。

現(xiàn)在問題完全明白了吧!你可以自己去演示一下。

__declspec (dllexport) void test(CString& str)

{

str = "abdefakdfj";//如果是static連接,并且傳入的str為空串的話,這里出錯。

}

posted on 2007-07-24 17:11 深邃者 閱讀(594) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产视频一区在线观看| 欧美精品 国产精品| 亚洲国产欧美日韩另类综合| 在线午夜精品自拍| 伊大人香蕉综合8在线视| 中日韩高清电影网| 9国产精品视频| 可以免费看不卡的av网站| 午夜精品久久久久| 欧美视频日韩视频在线观看| 欧美国内亚洲| 亚洲福利视频专区| 久久不射中文字幕| 久久久久久免费| 国产精品揄拍一区二区| 亚洲一区二区三区影院| 亚洲系列中文字幕| 欧美人与性禽动交情品| 亚洲国产精品成人va在线观看| 国产有码一区二区| 欧美一区二区在线| 久久久久国产精品一区三寸| 国产精品夜夜嗨| 亚洲专区在线视频| 亚洲欧美日韩另类| 国产精品拍天天在线| 99精品欧美一区二区三区综合在线| 亚洲精品影院| 欧美日韩在线播放| 99国产精品视频免费观看| 一区二区欧美日韩| 欧美日韩国产首页在线观看| 亚洲精品视频啊美女在线直播| 日韩亚洲一区在线播放| 欧美日韩成人在线视频| 一本色道久久加勒比88综合| 亚洲午夜性刺激影院| 国产精品免费视频观看| 欧美亚洲一区二区在线观看| 久久久综合激的五月天| 亚洲二区视频| 欧美日韩一区二区国产| 激情亚洲网站| 欧美激情一级片一区二区| 一本久久青青| 久久青草欧美一区二区三区| 亚洲高清视频在线| 欧美日韩国产亚洲一区| 亚洲在线观看| 嫩草成人www欧美| 99精品欧美一区| 国产精品无码永久免费888| 欧美一区视频| 亚洲国产黄色片| 亚洲免费在线| 韩国av一区二区三区在线观看| 久久免费国产精品| 99av国产精品欲麻豆| 久久精品男女| 亚洲精品一区二区三区四区高清| 国产精品theporn88| 欧美一区激情| 亚洲免费大片| 久久青草福利网站| 宅男噜噜噜66一区二区| 亚洲精品免费电影| 最近中文字幕日韩精品| 欧美精品成人一区二区在线观看 | 国产又爽又黄的激情精品视频 | 久久久综合免费视频| 亚洲国产精品激情在线观看| 午夜精品久久久久久| 亚洲欧洲另类国产综合| 国产精品免费看久久久香蕉| 欧美成年人网| 欧美综合激情网| 日韩一级视频免费观看在线| 麻豆91精品| 欧美在线视频二区| 一本色道久久综合亚洲精品按摩 | 中文久久乱码一区二区| 欧美高清在线观看| 欧美在线一区二区| 一区二区不卡在线视频 午夜欧美不卡在 | 国产精品区一区| 麻豆成人在线观看| 亚洲欧美精品中文字幕在线| 亚洲精品欧美日韩| 欧美激情第8页| 久久久久女教师免费一区| 亚洲午夜精品| 日韩视频一区二区三区| 狠狠综合久久av一区二区小说| 国产精品扒开腿做爽爽爽视频 | 欧美91大片| 久久久久国产精品一区| 午夜精品福利在线| 一二美女精品欧洲| 亚洲三级影片| 最新日韩欧美| 亚洲国产毛片完整版| 小处雏高清一区二区三区| 亚洲高清精品中出| 狠狠色香婷婷久久亚洲精品| 国产欧美一区二区视频| 国产精品网红福利| 国产精品午夜av在线| 国产精品成人一区二区三区吃奶| 欧美精品三级在线观看| 欧美理论电影在线播放| 欧美精品日韩| 欧美三级午夜理伦三级中视频| 欧美激情导航| 欧美日韩一区二区三区在线看| 欧美日产在线观看| 欧美伦理a级免费电影| 欧美日韩国产电影| 欧美日韩精品二区| 欧美午夜视频| 国产视频在线观看一区二区三区| 国产麻豆成人精品| 狠狠色狠狠色综合| 亚洲盗摄视频| 9国产精品视频| 欧美一级淫片aaaaaaa视频| 欧美一区二区三区精品电影| 久久久噜噜噜久久久| 欧美日本一道本| 久久综合国产精品| 久久一二三四| 欧美精品一区二区三区蜜臀| 欧美日韩综合另类| 国产精品一级二级三级| 韩日在线一区| 亚洲久色影视| 欧美在线免费看| 欧美国产1区2区| 一本一本a久久| 欧美中文字幕在线观看| 暖暖成人免费视频| 欧美特黄a级高清免费大片a级| 国产亚洲激情| 亚洲九九九在线观看| 欧美一区二区日韩一区二区| 美女网站久久| 一本色道久久综合亚洲精品不卡| 香蕉久久夜色精品国产使用方法 | 欧美激情bt| 国产视频亚洲精品| 亚洲精品视频中文字幕| 午夜欧美理论片| 国内精品写真在线观看| 性色一区二区三区| 久久一区二区精品| 欧美三级电影网| 伊人狠狠色丁香综合尤物| 一本色道久久综合亚洲精品婷婷| 欧美一区二区三区婷婷月色| 欧美成年人视频| 亚洲欧美日韩一区二区三区在线观看| 久久久久久欧美| 国产精品久久久久高潮| 亚洲精品黄网在线观看| 香港成人在线视频| 亚洲人午夜精品| 噜噜噜91成人网| 国产一区二区三区四区hd| 亚洲午夜一区二区三区| 亚洲国产精品成人精品| 久久精品国产精品| 国产模特精品视频久久久久| 99re亚洲国产精品| 欧美国产乱视频| 久久国产精品一区二区三区| 国产精品扒开腿爽爽爽视频| 亚洲美女在线一区| 欧美a级片网| 欧美伊人久久大香线蕉综合69| 欧美吻胸吃奶大尺度电影| 最新热久久免费视频| 蜜桃精品一区二区三区| 香港成人在线视频| 国产精品一级二级三级| 亚洲无亚洲人成网站77777| 亚洲国产精品www| 美女主播一区| 亚洲第一区在线| 美女主播视频一区| 久久精品人人做人人爽| 国产色视频一区| 久久精品国产精品亚洲精品| 亚洲欧美视频在线观看| 欧美午夜大胆人体| 亚洲午夜激情在线| 99伊人成综合| 国产精品激情偷乱一区二区∴| 国产精品99久久久久久人| 夜夜嗨av一区二区三区四季av| 欧美日韩中文字幕精品| 亚洲欧美成人|