本文介绍了为什么大多数 Delphi 示例使用 FillChar() 来初始化记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想知道,为什么大多数 Delphi 示例使用 FillChar() 来初始化记录.

I just wondered, why most Delphi examples use FillChar() to initialize records.

type
  TFoo = record
    i: Integer;
    s: string; // not safe in record, better use PChar instead
  end;

const
  EmptyFoo: TFoo = (i: 0; s: '');

procedure Test;
var
  Foo: TFoo;
  s2: string;
begin
  Foo := EmptyFoo; // initialize a record

  // Danger code starts
  FillChar(Foo, SizeOf(Foo), #0);
  s2 := Copy("Leak Test", 1, MaxInt); // The refcount of the string buffer = 1
  Foo.s = s2; // The refcount of s2 = 2
  FillChar(Foo, SizeOf(Foo), #0); // The refcount is expected to be 1, but it is still 2
end;
// After exiting the procedure, the string buffer still has 1 reference. This string buffer is regarded as a memory leak.

这里(http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html) 是我对这个主题的说明.IMO,用默认值声明一个常量是更好的方法.

Here (http://stanleyxu2005.blogspot.com/2008/01/potential-memory-leak-by-initializing.html) is my note on this topic. IMO, declare a constant with default value is a better way.

推荐答案

主要是历史原因.FillChar() 可以追溯到 Turbo Pascal 时代并用于此类目的.这个名字确实有点用词不当,因为它虽然说 FillChar(),但实际上是 FillByte().原因是最后一个参数可以带一个字符一个字节.所以 FillChar(Foo, SizeOf(Foo), #0) 和 FillChar(Foo, SizeOf(Foo), 0) 是等价的.另一个令人困惑的地方是,从 Delphi 2009 开始,FillChar 仍然只填充字节,即使 Char 等效于 WideChar.在查看 FillChar 的最常见用途以确定大多数人是使用 FillChar 实际用字符数据填充内存还是仅使用它用给定字节值初始化内存时,我们发现后一种情况主导了它的使用而不是前者.因此,我们决定让 FillChar 以字节为中心.

Historical reasons, mostly. FillChar() dates back to the Turbo Pascal days and was used for such purposes. The name is really a bit of a misnomer because while it says FillChar(), it is really FillByte(). The reason is that the last parameter can take a char or a byte. So FillChar(Foo, SizeOf(Foo), #0) and FillChar(Foo, SizeOf(Foo), 0) are equivalent. Another source of confusion is that as of Delphi 2009, FillChar still only fills bytes even though Char is equivalent to WideChar. While looking at the most common uses for FillChar in order to determine whether most folks use FillChar to actually fill memory with character data or just use it to initialize memory with some given byte value, we found that it was the latter case that dominated its use rather than the former. With that we decided to keep FillChar byte-centric.

确实,如果没有在适当的上下文中使用,使用 FillChar 清除包含使用托管"类型(字符串、变体、接口、动态数组)之一声明的字段的记录可能是不安全的.然而,在您给出的示例中,对本地声明的记录变量调用 FillChar 实际上是安全的,只要它是您对该范围内的记录所做的第一件事.原因是编译器已经生成了代码来初始化记录中的字符串字段.这已经将字符串字段设置为 0 (nil).调用 FillChar(Foo, SizeOf(Foo), 0) 只会用 0 个字节覆盖整个记录,包括已经为 0 的字符串字段.在记录变量 after 上使用 FillChar 一个值被分配给不推荐使用字符串字段.使用你的初始化常量技术是一个很好的解决这个问题的方法,因为编译器可以生成正确的代码来确保现有的记录值在赋值过程中正确完成.

It is true that clearing a record with FillChar that contains a field declared using one of the "managed" types (strings, Variant, Interface, dynamic arrays) can be unsafe if not used in the proper context. In the example you gave, however, it is actually safe to call FillChar on the locally declared record variable as long as it is the first thing you ever do to the record within that scope. The reason is that the compiler has generated code to initialize the string field in the record. This will have already set the string field to 0 (nil). Calling FillChar(Foo, SizeOf(Foo), 0) will just overwrite the whole record with 0 bytes, including the string field which is already 0. Using FillChar on the record variable after a value was assigned to the string field, is not recommended. Using your initialized constant technique is a very good solution this problem because the compiler can generate the proper code to ensure the existing record values are properly finalized during the assignment.

这篇关于为什么大多数 Delphi 示例使用 FillChar() 来初始化记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-17 08:46