Object objects[100];
这会实例化100个对象,对吗?在Delphi(特别是2007)中是否有可能这样做?除了以下方法之外还有其他的方式吗:
for i:=0 to 99 do
currentObject = TObject.Create;
或者使用Allocate
函数,传递TObject
大小的一百倍作为大小值,因为它只是分配内存,而不是将内存划分并“分配”给对象。
如果我的假设是c++实例化是瞬间完成而不是在幕后进行迭代,那我道歉。
Object objects[100];
for i:=0 to 99 do
currentObject = TObject.Create;
或者使用Allocate
函数,传递TObject
大小的一百倍作为大小值,因为它只是分配内存,而不是将内存划分并“分配”给对象。
如果我的假设是c++实例化是瞬间完成而不是在幕后进行迭代,那我道歉。
因此,这不是“语法糖”的缺失。
为了完全透明:
TForm
类的默认构造函数是什么? - kludg除了迭代,我不知道有什么非hacky的方法来做到这一点:
var
MyObjects: array[0..99] of TMyObject;
i: Integer;
begin
for i := 0 to 99 do
MyObjects[i] := TMyObject.Create;
end;
这个声明不会创建100个对象,它只会给你一个包含100个指向无用对象的引用数组。
创建一个对象是一个两步过程。第一步是分配内存(你的代码也没有做到),第二步是调用构造函数(Create方法)来初始化该内存、创建其他对象等等。
分配部分可以在循环外完成,但需要调用构造函数来初始化每个实例。
许多VCL类没有额外的构造函数。它们只有什么都不做的空构造函数。在这种情况下,就不需要调用它。
例如,要获取一个字符串列表数组,您可以使用以下代码,从此示例进行了调整:
type
TStringListArray = array of TStringList;v
var
Instances: array of Byte;
function GetStringLists(Number: Integer): TStringListArray;
var
i: Integer;
begin
// Allocate instance memory for all of them
SetLength(Instances, Number * TStringList.InstanceSize);
// Zero the memory.
FillChar(Instances[0], Length(Instances), 0);
// Allocate array for object references.
SetLength(Result, Number);
for i := 0 to High(Result) do
begin
// Store object reference.
Result[i] := @Instances[i * TStringList.InstanceSize];
// Set the right class.
PPointer(Result[i])^ := TStringList;
// Call the constructor.
Result[i].Create;
end;
end;
要获取一个包含100个字符串列表的数组:
var
x: TStringListArray;
begin
x := GetStringLists(100);
因此,尽管这个过程可能会为您节省一些时间(可忽略不计),并且在理论上可能更加内存高效(减少碎片化),但您仍然需要循环。没有捷径。
TStringListArray
,你还需要一些非平凡的终止代码。你不能调用 StringList[I].Free
。 - kludgSetLength(x, 100)
(其中 x 是 TStringListArray
)不能分配一个由 100 个 TStringList
组成的数组。我仍然盯着这段代码,试图弄清楚为什么需要这种“hack”。 - kobikSetLength(x, 100);
,for i := 0 to High(x) do x[i] := TStringList.Create;
不会创建相同的数组吗?也许我需要在 SO 上问一下我的问题... :) - kobik在Delphi中这是有点可能的(但在Delphi环境中并不是很实用,除非你正在编写自定义内存管理器)。创建对象实例是一个两步过程 - 为对象分配内存,并在该内存中构造对象的成员。没有什么要求给定对象的内存必须单独分配。您可以分配一个较大的内存块,并在该块内构造多个对象,利用Delphi的一个特性,如果从实例变量而不是类类型调用构造函数,则像普通方法一样调用构造函数,例如:
var
objects: array of Byte;
obj: TSomeClass;
begin
SetLength(objects, 100 * TSomeClass.InstanceSize);
FillChar(objects[0], 0, Length(objects));
for i := 0 to 99 do
begin
obj := TSomeClass.InitInstance(@objects[i * TSomeClass.InstanceSize]));
obj.Create;
end;
...
for i := 0 to 99 do
begin
obj := TSomeClass(@objects[i * TSomeClass.InstanceSize]);
obj.CleanupInstance;
end;
SetLength(objects, 0);
end;
这与在 C++ 中声明对象实例数组时的操作并没有太大区别,只不过 C++ 支持静态声明数组,并且会自动调用构造函数和析构函数,而 Delphi 不支持。
有许多第三方实现可以让您在堆栈或用户定义的缓冲区中分配对象,例如:
这只是其中的几个例子。
SetLength()
为动态数组分配的新内存在旧版 Delphi 中不能保证为零。手动将其清零不会有任何影响。 - Remy Lebeau
TObject* data[100];
只分配对象指针数组。无论如何,您必须使用data[i] = new TObject();
语法(或类似语法)创建对象实例,就像在Delphi或其他任何语言中一样。 - teranObject objects[100]
,前提是Object
不是TObject
的派生类。TObject
必须在堆上分配,这是Delphi的要求。C++中没有其他要求。 - Remy Lebeau