Is it safe to store visual components in a dynamic array?

Viewed 221

In delphi, if a dynamic array is reference counted, is it safe to store visual components in an array, as how would the reference counter work with a visual component? Could the reference counter be tricked since visual components are much different than regular non visual code...

I don't know if dynamic arrays in newer copies of delphi are memory managed some other way than reference counting, such as behind the scenes being implemented as some kind of List.

2 Answers

This is perfectly safe. Visual components aren't really any different from non visual components in terms of how instance variables are handled.

Reference counting of dynamic arrays can be thought of simply as automatic memory management of the array. Note that I said "of the array". Reference counting of dynamic arrays implies nothing about memory management of its elements.

An element of a dynamic array of TMyVisualComponent is simply a variable that holds a reference to an object. It's no different from a local variable of type TMyVisualComponent or a field of a class of type TMyVisualComponent.

Consider the following two examples:

type
  TMyClass1 = class
  private
    FObj: TMyVisualComponent;
  end;

  TMyClass2 = class
  private
    FArr: TArray<TMyVisualComponent>;
  end;

Into FObj is placed a reference to an instance whose lifetime is managed elsewhere. Likewise into FArr is placed references to multiple instances whose lifetimes are managed elsewhere.

When an instance of TMyClass1 is destroyed, nothing happens to the instance referred to by FObj. All that happens is that the instance of TMyClass1 is destroyed, and since it contains the variable FObj, then that variable too is destroyed. Note that I said "variable". The variable FObj is destroyed, the object to which it refers is not affected.

Similarly, when an instance of TMyClass2 is destroyed, the array FArr is destroyed, but nothing happens to the objects that it refers to.

One final wrinkle is that under the ARC compilers, all references to classes are reference counted. So what I said above needs to be modified to include reference counting of the instances of TMyVisualComponent. But since there are other parties that hold references to these instances of TMyVisualComponent, then they would remain alive throughout.

In summary then, simply think of TArray<TMyVisualComponent> as nothing more than multiple variables of TMyVisualComponent defined at the same scope.

Only a limited set of elements in Delphi are reference counted.
VCL components are not. They are not automatically destroyed by way of reference counting. Instead of reference counting VCL components use the concept of ownership. The owner of a VCL component is responsible for the destruction of all components it owns.

It is perfectly safe to store (references to) VCL components in an array, dynamic or otherwise.

Dynamic arrays are the same they have been since their introduction in D4. A simple array, allocated on the heap, that is reference counted.

Note that the fact that the array containing items is reference counted does not in any way affect the things contained therein. The refcount of the array does not go up if you store more items in it. It only goes up if you increase the number of references to the array, like so:

function Test: TArray<TComponent>;
var
  a: TArray<TComponent>
begin
  SetLength(a, 100);  //first use of a, refcount = 1
  a[0]:= Button1;  //nothing happens
  Result:= a;   //increases refcount of a to 2.
end; //end of scope for a, refcount of a decreased to 1.

procedure Test2;
var
  x: TArray<TComponent>
begin
  x:= Test;  //x = Test.a, refcount of x = 1
  x[1]:= Button2; //nothing happens
end; //end of scope for x, refcount = 0, x is freed.
//nothing happens to button1 and button2, because VCL components are not reference counted.

If you store reference counted items in a dynamic array, then their refcount will be decreased (destroying them if that brings their refcount to 0) when the dynamic array is destroyed. Refcounted types are:

  • Strings
  • Dynamic arrays (yes, you can nest them)
  • Interfaces
  • Classes in ARC compilers (Mobile, Linux)

Note that whilst you can get an interface reference to a VCL class, the refcount of a VCL class is fixed to -1 (meaning _Addref and _Release are dummy methods that do nothing).

Related