Inc(pdw); dw2 := pdw^;
Inc(pdw); dw3 := pdw^;
ListBox1.Items.Add( Format(''''[After COW]Size:%d, Ref:%d, Len:%d'''',
[dw1,dw2,dw3]) );
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
ListBox1.Items.Clear;
end;
如果你对指针的概念比较清楚的话,上面的代码是不难理解的。下面是该程序的输出结果:
[Current]Size:22, Ref:5, Len:5
[Before Assign]Size:22, Ref:2, Len:5
[After Assign]Size:22, Ref:3, Len:5
[After COW]Size:22, Ref:2, Len:5
观察上述结果,可以得出几个结论:
1.“分配大小”和“字串长度”之间存在着一种固定的数量关系,即分配大小=字串长度+17。为什么会有这种关系?请你再看一看String类型的内存分布:(4字节)分配大小+(4字节)引用计数+(4字节)字串长度+(不定长)字符数组+(1字节)$0结束字符,4+4+4+(strlen)+1,应该是13+(strlen)才对,也就是说应该还有4字节的空间,其用途尚不清楚。值得一提的是,如果你将字符串清空,那么Len的结果可能不是你所想象的0,而是一个让你大吃一惊的数字。
2.因为分配大小和字串长度都是用4字节来表示的,而且String类型是动态分配内存,所以字符串最大可能的长度应该是2^32-17个字节。
3.在拷贝字符串的时候,Object Pascal并不是把字符串简单的复制一份,而是采取了引用计数的方法,将两个字符串指向同一个内存空间,同时引用计数加1。当字符串变量被清除的时候,引用计数减1,如果引用计数已经减为0,表明该字符串可以真正被清除了。显然,这种方法比复制整个字符串的效率要高。
4.在给字符串赋值的时候,Object Pascal首先会检查字符串的引用计数是否为1。如果是,按照一般的方法直接赋值即可;否则,就说明有两个以上字符串指向同一个地址,这种情况就复杂多了。Object Pascal使用的是Copy-on-Write机制(COW),为当前字符串另外开辟一个缓冲区,将新内容拷入;同时,原来的字符串引用计数要减一。
5.知道了String的内存布局,我们也就知道了PChar(str)的意义了。不过,使用PChar的同时也就丢失了String的动态增长和引用计数的功能,所以一定要小心,另外要注意PChar长度的计算和字符串长度一定要同步,否则会出问题。比如,下面的代码就不能正常工作:
var
str : string;
begin
SetLength(str,256);
GetWindowDirectory(PChar(str),256);
str := str + ‘\win.ini’;
end;
这样的结果是不正确的。之所以不正确,是因为SetLength将字符串长度设成了256,而PChar计算的长度只到第一个$0为止。正确的方法应该是:
SetLength(str,256);
GetWindowsDirectory(PChar(str),256);
SetLength(str,StrLen(PChar(str)));
str := setr + ‘\win.ini’;
说明:上面的程序是在Delphi 5下测试通过的。Borland并不保证String的内存结构在以后的Delphi版本中会保持不变,所以,上述例子只是作为测试用,实际的程序中不应该这样使用String,谨此说明。
上一页 [1] [2] [系统软件]14.5.10.1 Object creation expressions [VB.NET程序]VB.Net中文教程(8) 对象(Object)基本概念 [VB.NET程序]Read a string at a given address [VB.NET程序]MCI Command String总览 [Delphi程序]The Delphi Object Model (PART III) [Delphi程序]The Delphi Object Model (PART II) [Delphi程序]The Delphi Object Model (PART I) [Delphi程序]Object Pascal:从对象指针谈起 [Delphi程序]浅谈Object Pascal的指针 [Delphi程序]kmp模式匹配算法的pascal实现
|