??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品成人久久久久三级午夜电影,久久亚洲AV无码精品色午夜,成人亚洲欧美久久久久http://m.shnenglu.com/yunboy4/archive/2009/07/31/91800.htmlyunboyyunboyFri, 31 Jul 2009 05:46:00 GMThttp://m.shnenglu.com/yunboy4/archive/2009/07/31/91800.htmlhttp://m.shnenglu.com/yunboy4/comments/91800.htmlhttp://m.shnenglu.com/yunboy4/archive/2009/07/31/91800.html#Feedback0http://m.shnenglu.com/yunboy4/comments/commentRss/91800.htmlhttp://m.shnenglu.com/yunboy4/services/trackbacks/91800.htmlCString详细讲解
 前言Q串操作是编E中最常用也最基本的操作之一?做ؓVCE序员,无论是菜鸟或高手都曾用过Cstring。而且好像实际~程中很隄得开它(虽然它不是标准E++中的库)。因为MFC中提供的q个cd我们操作字串实在太方便了QCString不仅提供各种丰富的操作函数、操作符重蝲Q我们使用起串h更象basic中那L观;而且它还提供了动态内存分配,使我们减了多少字符串数l越界的隐患。但是,我们在用过E中也体会到CString直太Ҏ出错了,而且有的不可捉摸。所以有许多高h站过来,抛弃它?

在此Q我个h认ؓQCString装得确实很完美Q它有许多优点,?#8220;Ҏ使用 Q功能强Q动态分配内存,大量q行拯时它很能节省内存资源q且执行效率高,与标准E完全兼容Q同时支持多字节与宽字节Q由于有异常机制所以用它安全方便” 其实Q用过E中之所以容易出错,那是因ؓ我们对它了解得还不够Q特别是它的实现机制。因为我们中的大多数人,在工作中q不那么爱深入地ȝ关于它的文Q何况它q是英文的?

׃前几天我在工作中遇到了一个本不是问题但却特别手、特别难解决而且莫名惊诧的问题。好来最后发现是׃CString引发的。所以没办法Q我把整个CString的实现全部看了一遍,才慌然大悟,q彻底弄清了问题的原?q个问题Q我已在csdn上开?。在此,我想把我的一些关于CString的知识ȝ一番,以供他(她)人借鉴Q也许其中有我理解上的错误,望发现者能通知我,不胜感谢?/p>


1Q?CString实现的机?

CString是通过“引用”来管理串的,“引用”q个词我怿大家q不陌生Q象Window内核对象、COM对象{都是通过引用来实现的。而CString也是通过q样的机制来理分配的内存块。实际上CString对象只有一个指针成员变?所以Q何CString实例的长度只?字节.

? int len = sizeof(CString);//len{于4

q个指针指向一个相关的引用内存块,如图: CString str("abcd");

 

 


‘A’

‘B’

‘C’

‘D’

0

 

 

0x04040404 head部,为引用内存块相关信息


str 0x40404040

 

 


正因为如此,一个这L内存块可被多个CString所引用Q例如下列代码:

CString str("abcd");

CString a = str;

CString b(str);

CString c;

c = b;

上面代码的结果是Q上面四个对?str,a,b,c)中的成员变量指针有相同的|都ؓ0x40404040.而这块内存块怎么知道有多个CString引用它呢Q同P它也会记录一些信息。如被引用数Q串长度Q分配内存长度?/p>

q块引用内存块的l构定义如下Q?/p>

struct CStringData

{

long nRefs; //表示有多个CString 引用? 4

int nDataLength; //串实际长? 4

int nAllocLength; //d分配的内存长度(不计q头部的12字节Q? 4

};

׃有了q些信息QCStringp正确地分配、管理、释攑ּ用内存块?/p>

如果你想在调试程序的时候获得这些信息。可以在WatchH口键入下列表达式:

(CStringData*)((CStringData*)(this->m_pchData)-1)?/p>

(CStringData*)((CStringData*)(str.m_pchData)-1)//str为指CString实例


正因为采用了q样的好机制Q得CString在大量拷贝时Q不仅效率高Q而且分配内存?/p>

 

2QLPCTSTR ?GetBuffer(int nMinBufLength)

q两个函数提供了与标准C的兼容{换。在实际中用频率很高,但却是最Ҏ出错的地斏V这两个函数实际上返回的都是指针Q但它们有何区别呢?以及调用它们后,q后是做了怎样的处理过E呢Q?/p>

(1) LPCTSTR 它的执行q程其实很简单,只是q回引用内存块的串地址?它是作ؓ操作W重载提供的Q所以在代码中有时可以隐式{换,而有时却需强制转制。如Q?/p>

CString str;

const char* p = (LPCTSTR)str;

//假设有这L一个函敎ͼTest(const char* p)Q?你就可以q样调用

Test(str);//q里会隐式{换ؓLPCTSTR

(2) GetBuffer(int nMinBufLength) 它类|也会q回一个指针,不过它有点差?q回的是LPTSTR

(3) q两者到底有何不同呢Q我惛_诉大Ӟ其本质上完全不一P一般说LPCTSTR转换后只应该当常量用,或者做函数的入参;而GetBuffer(...)取出指针后,可以通过q个指针来修攚w面的内容Q或者做函数的出参。ؓ什么呢Q也许经常有q样的代码:

CString str("abcd");

char* p = (char*)(const char*)str;

p[2] = 'z';

其实Q也许有q样的代码后Q你的程序ƈ没有错,而且E序也运行得挺好。但它却是非常危险的。再?/p>

CString str("abcd");

CString test = str;

....

char* p = (char*)(const char*)str;

p[2] = 'z';

strcpy(p, "akfjaksjfakfakfakj");//q下完蛋?

你知道此Ӟtest中的值是多少吗?{案?abzd"。它也跟着改变了,q不是你所期望发生的。但Z么会q样呢?你稍微想惛_会明白,前面说过Q因为CString是指向引用块的,str与test指向同一块地?当你p[2]='z'后,当然test也会随着改变。所以用它做LPCTSTR做{换后Q你只能去读q块数据Q千万别L变它的内宏V?/p>


假如我想直接通过指针MҎ据的话,那怎样办呢Q就是用GetBuffer(...).看下qC码:

CString str("abcd");

CString test = str;

....

char* p = str.GetBuffer(20);

p[2] = 'z'; // 执行到此Q现在test中值却仍是"abcd"

strcpy(p, "akfjaksjfakfakfakj"); // 执行到此Q现在test中D?abcd"

Z么会q样Q其实GetBuffer(20)调用Ӟ它实际上另外建立了一块新内块存,q分?0字节长度的bufferQ而原来的内存块引用计C相应?. 所以执行代码后str与test是指向了两块不同的地方,所以相安无事?/p>

(4) 不过q里q有一Ҏ意事:是str.GetBuffer(20)后,str的分配长度ؓ20Q即指针p它所指向的buffer只有20字节长,l它赋值时Q切不可过Q否则灾隄你不q了Q如果指定长度小于原来串长度Q如GetBuffer(1),实际上它会分?个字节长度(卛_来串长度Q;另外Q当调用GetBuffer(...)后ƈ改变其内容,一定要记得调用ReleaseBuffer(),q个函数会根据串内容来更新引用内存块的头部信息?/p>

(5) 最后还有一注意事项Q看下述代码Q?/p>

char* p = NULL;

const char* q = NULL;

{

CString str = "abcd";

q = (LPCTSTR)str;

p = str.GetBuffer(20);

AfxMessageBox(q);// 合法?/p>

strcpy(p, "this is test");//合法的,

}

AfxMessageBox(q);// 非法的,可能完蛋

strcpy(p, "this is test");//非法的,可能完蛋

q里要说的就是,当返回这些指针后Q?如果CString对象生命l束Q这些指针也相应无效?/p>


3Q拷?& 赋?& "引用内存? 什么时候释放?


下面演示一D代码执行过E?/p>

void Test()

{

CString str("abcd");

//str指向一引用内存块(引用内存块的引用计数?,长度?,分配长度?Q?/p>

CString a;

//a指向一初始数据状态,

a = str;

//a与str指向同一引用内存块(引用内存块的引用计数?,长度?,分配长度?Q?/p>

CString b(a);

//a、b与str指向同一引用内存块(引用内存块的引用计数?,长度?,分配长度?Q?/p>

{

LPCTSTR temp = (LPCTSTR)a;

//temp指向引用内存块的串首地址。(引用内存块的引用计数?,长度?,分配长度?Q?/p>

CString d = a;

//a、b、d与str指向同一引用内存块(引用内存块的引用计数?, 长度?,分配长度?Q?/p>

b = "testa";

//q条语句实际是调用CString::operator=(CString&)函数?b指向一新分配的引用内存块。(新分配的引用内存块的 引用计数?, 长度?, 分配长度?Q?/p>

//同时原引用内存块引用计数?. a、d与str仍指向原 引用内存块(引用内存块的引用计数?,长度?,分配长度?Q?

}

//׃d生命l束Q调用析构函敎ͼD引用计数?Q引用内存块的引用计Cؓ2,长度?,分配长度?Q?/p>

LPTSTR temp = a.GetBuffer(10);

//此语句也会导致重新分配新内存块。temp指向新分配引用内存块的串首地址Q新 分配的引用内存块的引用计Cؓ1,长度?,分配长度?0Q?/p>

//同时原引用内存块引用计数?. 只有str?指向原引用内存块 Q引用内存块的引用计Cؓ1, 长度?, 分配长度?Q?

strcpy(temp, "temp");

//a指向的引用内存块的引用计Cؓ1,长度?,分配长度?0 a.ReleaseBuffer();//注意:a指向的引用内存块的引用计Cؓ1,长度?,分配长度?0

}

//执行到此Q所有的局部变量生命周期都已结束。对象str a b 各自调用自己的析构构

//函数Q所指向的引用内存块也相应减1

//注意Qstr a b 所分别指向的引用内存块的计数均?,q导致所分配的内存块释放


通过观察上面执行q程Q我们会发现CString虽然可以多个对象指向同一引用内块存,但是它们在进行各U拷贝、赋值及改变串内ҎQ它的处理是很智能ƈ且非常安全的Q完全做C互不q涉、互不媄响。当然必要求你的代码用正恰当,特别是实际用中会有更复杂的情况Q如做函数参数、引用、及有时需保存到CStringList当中Q如果哪怕有一块地方使用不当Q其l果也会D发生不可预知的错?/p>


5 FreeExtra()的作?/p>

看这D代?/p>

(1) CString str("test");

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

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

(4) str.ReleaseBuffer();

(5) str.FreeExtra();

上面代码执行到第(4)行时Q大安知道str指向的引用内存块计数?,长度?2,分配长度?0. 那么执行str.FreeExtra()Ӟ它会释放所分配的多余的内存?引用内存块计Cؓ1,长度?2,分配长度?2)


6 Format(...) ?FormatV(...)

q条语句在用中是最Ҏ出错的。因为它最富有技巧性,也相当灵zR在q里Q我没打对它细l分析,实际上sprintf(...)怎么用,它就怎么用。我只提醒用时需注意一点:是它的参数的特D性,׃~译器在~译时ƈ不能L验格式串参数与对应的变元的类型及长度。所以你必须要注意,两者一定要对应上,

否则׃出错。如Q?/p>

CString str;

int a = 12;

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


7 LockBuffer() ?UnlockBuffer()

֐思议Q这两个函数的作用就是对引用内存块进行加锁及解锁。但使用它有什么作用及执行q它后对CString串有什么实质上的媄响。其实挺单,看下面代?

(1) CString str("test");

(2) str.LockBuffer();

(3) CString temp = str;

(4) str.UnlockBuffer();

(5) str.LockBuffer();

(6) str = "error";

(7) str.ReleaseBuffer();

执行?3)后,与通常情况下不同,temp与strq不指向同一引用内存块。你可以在watchH口用这个表辑ּ(CStringData*)((CStringData*)(str.m_pchData)-1)看看?/p>

其实在msdn中有说明Q?/p>

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 只是处理串吗Q?/p>

不对QCString不只是能操作Ԍ而且q能处理内存块数据。功能完善吧Q看q段代码

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完全能够转蝲内存块p到内存块temp中。所以能用CString来处理二q制数据


8 AllocSysString()与SetSysString(BSTR*)

q两个函数提供了串与BSTR的{换。用时L意一点:当调用AllocSysString()后,调用它SysFreeString(...)


9 参数的安全检?/p>

在MFC中提供了多个宏来q行参数的安全检查,如:ASSERT. 其中在CString中也不例外,有许多这L参数验,其实q也说明了代码的安全性高Q可有时我们会发现这很烦Q也DDebug与Release版本不一P如有时程序Debug通正常,而Release则程序崩溃;而有时恰相反QDebug不行QRelease行。其实我个h认ؓQ我们对CString的用过E中Q应力求代码质量高,不能在Debug版本中出CQ何断a框,哪怕releaseq行g看v来一切正常。但很不安全。如下代码:

(1) CString str("test");

(2) str.LockBuffer();

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

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

(5) str.ReleaseBuffer();

(6) str.ReleaseBuffer();//执行到此ӞDebug版本会弹出错?/p>


10 CString的异常处?/p>

我只惛_调一点:只有分配内存Ӟ才有可能D抛出CMemoryException.

同样Q在msdn中的函数声明中,注有throw( CMemoryException)的函数都有重新分配或调整内存的可能?/p>


11 跨模块时的Cstring。即一个DLL的接口函C的参CؓCString&Ӟ它会发生怎样的现象。解{我遇到的问题。我的问题原来已l发_地址为:

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


构造一个这样CString对象Ӟ如CString strQ你可知道此时的str所指向的引用内存块吗?也许你会认ؓ它指向NULL。其实不对,如果q样的话QCString所采用的引用机制管理内存块׃有麻烦了Q所以CString在构造一个空串的对象Ӟ它会指向一个固定的初始化地址Q这块数据的声明如下Q?/p>

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

要描q概括一下:当某个CString对象串置I的话,如Empty(),CString a{,它的成员变量m_pchData׃指向_afxInitDataq个变量的地址。当q个CString对象生命周期l束Ӟ正常情况下它会去Ҏ指向的引用内存块计数?Q如果引用计Cؓ0(x有Q何CString引用它时)Q则释放q块引用内存。而现在的情况是如果CString所指向的引用内存块是初始化内存块时Q则不会释放M内存?/p>


说了q么多,q与我遇到的问题有什么关pdQ其实关pd着呢?其真正原因就是如果exe模块与dll模块有一个是static~译q接的话。那么这个CString初始化数据在exe模块与dll模块中有不同的地址Q因为staticq接则会在本模块中有一份源代码的拷贝。另外一U情况,如果两个模块都是shareq接的,CString的实C码则在另一个单独的dll中实玎ͼ而AFX_STATIC_DATA指定变量只装一ơ,所以两个模块中_afxInitData有相同的地址?/p>

现在问题完全明白了吧Q你可以自己LCZ下?/p>

__declspec (dllexport) void test(CString& str)

{

str = "abdefakdfj";//如果是staticq接Qƈ且传入的str为空串的话,q里出错?/p>

}


最后一Ҏ法:写得q里Q其实CString中还有许多技巧性的好东东,我ƈ没去解释。如很多重蝲的操作符、查扄。我认ؓq是详细看看msdnQ这样也怼比我讲的好多了。我只侧重那些可能会出错的情c当Ӟ如我上面叙述中有错误Q敬请高手指点,不胜感谢Q?/p>


msdnQ?a >http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp



yunboy 2009-07-31 13:46 发表评论
]]>
99þþƷҹһ| ҹҹþݺ| һɫþۺ޾Ʒ| Ʒþþþ| ƷþòҰ| þþþƷƵѹۿ| þþþþùƷ | þþƷav鶹ͼƬ | 7777Ʒþþô߽| ˾þˬ| ɫۺϾþ| þ޾ƷĻ| þþþӰԺŮ| ɫۺϾþ߹ۿ| ݺݸɺݺݾþ| AVþüįٸ| ĻƷѾþ5151| Ʒ99þþþƷ| Ѹþ| þô㽶| ݺɫþþۺƵպ | þ߿ۿƷ㽶| ѾþþƷ99reѾy| 88þþƷһëƬ | ɫۺϾžþ| þۺĻ| Ʒþþþþþþҹ| þþþĻɫ| Ʒþþþ㽶| ŮþþŮ| þAV뾫Ʒ| ˾Ʒþ޸岻| ҹѸþӰԺ | þۺϾþۺϾɫ| þþȹ͵ۺ| ޾Ʒҹvaþ| ҹþAAAAAëƬѿ| Ʒþþ99| þþƷƷëƬ| þۺϸۺϾþ| ɫۺϺϾþۿ|