使用来自数组的值时,CompareMem似乎不起作用

时间:2015-09-02 02:03:42

标签: delphi

所以我的程序中有一个测试用例

MemCheck<String>('a', 'a');

此测试用例失败,我不确定原因

c := a ;

使用

时效果很好

c := T(vals[2]);代替UISearchController

1 个答案:

答案 0 :(得分:16)

您正在将字符串文字传递给MemCheck()。由于它们是相同的值,因此编译器将它们合并在可执行文件中。因此,您实际上将一个常量字符串文字传递给xy参数。字符串文字是只读的,引用计数为-1。将字符串文字分配给String变量将指针按原样复制到内存块,而不分配新内存或增加内存块的引用计数。

在填充vals数组之前,您的abc变量只是字符串文字指针的副本。它们都指向内存中的相同数据块。 System.StringRefCount()函数确认它们都返回引用计数-1,证明它们都指向字符串文字。

在语句vals[2] := a;中,a指向字符串文字,因此RTL分配新的String实例,并将字符串文字的内容复制到新的内存块中。 a仍然具有-1的引用计数,但vals[2]现在的引用计数为1,证明已执行分配。然后,语句c := T(vals[2]);将分配的String分配给String变量,因此分配的数据的引用计数会递增。 StringRefCount()确认c现在的引用计数为2.

然后

CompareMem()失败,因为你正在比较指向两个不同内存块的两个String变量的内部数据指针的值,因此它们的指针值不同,比较失败。

当您将语句c := T(vals[2]);更改为c := a;时,a仍然指向内存中的字符串文字,因此指针会按原样复制到c中执行任何分配。因此CompareMem()成功,因为现在您正在比较指向同一内存块的两个String变量的内部数据指针的值,因此比较成功。

所以真正的问题是 - 为什么语句vals[2] := a;执行新的分配而不是仅仅复制数据指针就像任何其他String := String;赋值一样?

分配a := x;b := y;c := a;正在调用System.@UStrLAsg()函数,该函数允许指向字符串文字的String指定为 - 是在没有执行分配的情况下转到另一个String

语句vals[2] := a;正在调用System.@UStrAsg()函数,当源String指向字符串文字时,总是创建一个新的已分配副本。

为什么编译器选择在@UStrAsg()语句中使用@UStrLAsg()而不是vals[2] := a;?这就是当赋值的左侧是动态数组中的String而不是独立变量时编译器的工作方式。如果vals是静态数组(vals: array[0..3] of String;),则编译器会选择使用@UStrLAsg()而不是@UStrAsg(),然后CompareMem()会成功。

@UStrLAsg()通常在将String分配给本地 String时使用,因此通常可以安全地使用字符串文字作为 - 是

@UStrAsg()通常在将String分配给全局 String时使用,其中需要复制文字以避免文字时出现潜在的内存错误可能存在于可在分配后卸载的DLL /包中。

因此,在分配给动态数组时,编译器必须小心谨慎,因为它不知道或不能假设数组中String个实例的生命周期。