Reputation: 1376
I think that C++ supports something on the lines of :
Object objects[100];
This would instantiate a 100 objects, right? Is it possible to do this in Delphi (specifically 2007)? Something other than:
for i:=0 to 99 do
currentObject = TObject.Create;
or using the Allocate
function, with a passed size value a hundred times the TObject
size, because that just allocates memory, it doesn't actually divide the memory and 'give' it to the objects.
If my assumption that the c++ instantiation is instant rather than under-the-hood-iterative, I apologize.
Upvotes: 4
Views: 1190
Reputation: 597285
It is somewhat possible in Delphi (but is not very practical in a Delphi environment, unless you are writing a custom memory manager). Creating an object instance is a two-step process - allocating memory for the object, and constructing the object's members inside of that memory. There is nothing requiring the memory of a given object to be allocated individually. You can allocate a larger block of memory and construct multiple objects inside of that block, taking advantage of a feature of Delphi that calls a constructor like a normal method if it is called from an instance variable instead of a class type, eg:
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;
This is not much different than what C++ does behind the scenes when declaring an array of object instances, only C++ supports declaring the array statically and it will call the constructors and destructors automatically, whereas Delphi does not support that.
There are a number of third-party implementations that allow you to allocate objects on the stack or in user-defined buffers, such as:
Objects on the Stack: A Delphi Relic
Allocate objects on stack, at specified memory address, or through any memory manager
Just to name a couple.
Upvotes: 1
Reputation: 51000
While you can't do what you want using objects, if your objects are relatively simple, you may be able to get what you want by using an array of records.
Records in Delphi can have properties (including setters and getters), and class and instance methods. They are created automatically when declared, so declaring an array of them will create them all without iterating.
For more info: http://docwiki.embarcadero.com/RADStudio/XE3/en/Structured_Types#Records_.28advanced.29.
(I'm not sure when the new functionality was added to Delphi, it may well be after the 2007 version).
Upvotes: 5
Reputation: 27493
What you are looking for is impossible because
So that is not a lack of 'sugar syntax'.
For the sake of complete disclosure:
Upvotes: 5
Reputation: 116160
That declaration wouldn't create 100 objects, it would just give you an array of 100 object references that point to nothing useful.
Creating an object is a two step process. The first step is allocating memory (which your code also doesn't), the second step is calling the constructor (Create method) to initialize that memory, create additional objects, etc, etc.
The allocation part can be done without the loop, but the constructor needs to be called to intialize each instance.
Many VCL classes don't have an additional constructor. They just have the empty constructor that does nothing. In that case, there is no need to call it.
For instance, to fetch an array of stringlists, you can use the following code, adjusted from this example:
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;
And to get an array of 100 stringlists:
var
x: TStringListArray;
begin
x := GetStringLists(100);
So while this procedure may save you a neglectable amount of time, and may theoretically be more memory-efficient (less fragmentation), you will still need the loop. No easy way out.
Upvotes: 1
Reputation: 14001
I don't know of any non-hacky way to do this besides iterating:
var
MyObjects: array[0..99] of TMyObject;
i: Integer;
begin
for i := 0 to 99 do
MyObjects[i] := TMyObject.Create;
end;
Upvotes: 2