CString( 九 )

比起下面的代码来,效率要低多了:char s[1024];lstrcpy(s,SomeString1);lstrcat(s,SomeString2);lstrcat(s,SomeString3);lstrcat(s,",");lstrcat(s,SomeString4);总之,你可能会想,首先,它为 SomeCString1 分配一块记忆体,然后把 SomeCString1 複製到里面,然后发现它要做一个连线,则重新分配一块新的足够大的记忆体,大到能够放下当前的字元串加上SomeCString2,把内容複製到这块记忆体 ,然后把 SomeCString2 连线到后面,然后释放第一块记忆体,并把指针重新指向新记忆体 。然后为每个字元串重複这个过程 。把这 4 个字元串连线起来效率多低啊 。事实上,在很多情况下根本就不需要複製源字元串(在 += 操作符左边的字元串) 。在 VC++6.0 中,Release 模式下,所有的 CString 中的快取都是按预定义量子分配的 。所谓量子,即确定为 64、128、256 或者 512 位元组 。这意味着除非字元串非常长,连线字元串的操作实际上就是 strcat 经过最佳化后的版本(因为它知道本地的字元串应该在什幺地方结束,所以不需要寻找字元串的结尾;只需要把记忆体中的数据拷贝到指定的地方即可)加上重新计算字元串的长度 。所以它的执行效率和纯 C 的代码是一样的,但是它更容易写、更容易维护和更容易理解 。如果你还是不能确定究竟发生了怎样的过程,请看看 CString 的原始码,strcore.cpp,在你 vc98的安装目录的 mfc\src 子目录中 。看看 ConcatInPlace 方法,它被在所有的 += 操作符中调用 。啊哈!难道 CString 真的这幺"高效"吗?比如,如果我创建CString cat("Mew!");然后我并不是得到了一个高效的、精简的5个位元组大小的缓冲区(4个字元加一个结束字元),系统将给我分配64个位元组,而其中59个位元组都被浪费了 。如果你也是这幺想的话,那幺就请準备好接受再教育吧 。可能在某个地方某个人给你讲过儘量使用少的空间是件好事情 。不错,这种说法的确正确,但是他忽略了事实中一个很重要的方面 。如果你编写的是运行在16K EPROMs下的嵌入式程式的话,你有理由儘量少使用空间,在这种环境下,它能使你的程式更健壮 。但是在 500MHz,256MB的机器上写 Windows 程式,如果你还是这幺做,它只会比你认为的"低效"的代码运行得更糟 。举例来说 。字元串的大小被认为是影响效率的首要因素,使字元串儘可能小可以提高效率,反之则降低效率,这是大家一贯的想法 。但是这种想法是不对的,精确的记忆体分配的后果要在程式运行了好几个小时后才能体现得出来,那时,程式的堆中将充满小片的记忆体,它们太小以至于不能用来做任何事,但是他们增加了你程式的记忆体用量,增加了记忆体页面交换的次数,当页面交换的次数增加到系统能够忍受的上限,系统则会为你的程式分配更多的页面,直到你的程式占用了所有的可用记忆体 。由此可见,虽然记忆体碎片是决定效率的次要因素,但正是这些因素实际控制了系统的行为,最终,它损害了系统的可靠性,这是令人无法接受的 。记住,在 debug 模式下,记忆体往往是精确分配的,这是为了更好的排错 。假设你的应用程式通常需要连续工作好几个月 。比如,我常打开 VC++,Word,PowerPoint,Frontpage,Outlook Express,Forté Agent,Internet Explorer和其它的一些程式,而且通常不关闭它们 。我曾经夜以继日地连续用 PowerPoint 工作了好几天(反之,如果你不幸不得不使用像 Adobe FrameMaker 这样的程式的话,你将会体会到可靠性的重要;这个程式机会每天都要崩溃4~6次,每次都是因为用完了所有的空间并填满我所有的交换页面) 。所以精确记忆体分配是不可取的,它会危及到系统的可靠性,并引起应用程式崩溃 。按量子的倍数为字元串分配记忆体,记忆体分配器就可以回收用过的记忆体块,通常这些回收的记忆体块马上就可以被其它的 CString 对象重新用到,这样就可以保证碎片最少 。分配器的功能加强了,应用程式用到的记忆体就能儘可能保持最小,这样的程式就可以运行几个星期或几个月而不出现问题 。题外话:很多年以前,我们在 CMU 写一个互动式系统的时候,一些对记忆体分配器的研究显示出它往往产生很多记忆体碎片 。Jim Mitchell,他在 Sun Microsystems 工作,那时候他创造了一种记忆体分配器,它保留了一个记忆体分配状况的运行时统计表,这种技术和当时的主流分配器所用的技术都不同,且较为领先 。当一个记忆体块需要被分割得比某一个值小的话,他并不分割它,因此可以避免产生太多小到什幺事都干不了的记忆体碎片 。事实上他在记忆体分配器中使用了一个浮动指针,他认为:与其让指令做长时间的存取记忆体操作,还不如简单的忽略那些太小的记忆体块而只做一些浮动指针的操作 。(His observation was that the long-term saving in instructions by not having to ignore unusable small storage chunks far and away exceeded the additional cost of doing a few floating point operations on an allocation operation.)他是对的 。永远不要认为所谓的"最最佳化"是建立在每一行代码都高速且节省记忆体的基础上的,事实上,高速且节省记忆体应该是在一个应用程式的整体水平上考虑的 。在软体的整体水平上,只使用最小记忆体的字元串分配策略可能是最糟糕的一种方法 。如果你认为最佳化是你在每一行代码上做的那些努力的话,你应该想一想:在每一行代码中做的最佳化很少能真正起作用 。记住,+= 运算符只是一种特例,如果你写成下面这样:CString s = SomeCString1 + SomeCString2 + SomeCString3 + "," + SomeCString4;则每一个 + 的套用会造成一个新的字元串被创建和一次複製操作 。总结以上是使用 CString 的一些技巧 。我每天写程式的时候都会用到这些 。CString 并不是一种很难使用的类,但是 MFC 没有很明显的指出这些特徵,需要你自己去探索、去发现 。