Thursday, January 8, 2015

Smart pointers in Delphi

Yes, I know - I am way too late to that party.

But this is yet another thing that the language itself is missing but can be done with some tricks as the posts showed. However I felt in all these implementations something was missing. Barry's first implementations were record based which had the disadvantage of always having to write .Value when accessing the actual instance. I prefer his latest approach using an anonymous method type. The approach shown in the ADUG blog uses the constructor constraint to be able to create the instance inside the TSmartPointer<T> which is also appealing.

However all these were missing something that could be done with a smart pointer as well. Allocate space for a typed pointer and manage that.

So Spring4D 1.2 (release date tba) will - among many other cool new things - contain a smart pointer implementation.

Code that looked like this until now:

var
  s: TStrings;
begin
  s := TStringList.Create;
  try
    DoSomething(s);
  finally
    s.Free;
  end;
end;

Will look like this:

var
  s: IShared<TStrings>;
begin
  s := Shared<TStringList>.New;
  DoSomething(s);
end;

or:

var
  s: Shared<TStrings>;
begin
  s := TStringList.Create;
  DoSomething(s);
end;

The first is using the interface based (anonymous method to be more precise) smart pointer where you don't need to write .Value when accessing the instance.

The second code is using the record based type where you have to write .Value to access the actual instance but it supports implicit casting from and to the actual type. That is why you can directly assign the TStringList to it and also pass it to the routine.

Here is another example of how to manage some typed pointer:

var
  s: IManaged<PMyRecord>;
begin
  s := Shared<PMyRecord>.New;
  s.num := 42;
  s.text := 'Hello world';
end;

In this code the smart pointer will allocate memory for the record and properly finalize and free the memory when it goes out of scope.

Now it would be cool if on a record type you could specify a property as default so it does member lifting in order to get rid of having to type .Value when accessing the underlying value. Especially when the record does not have any other members anyway. That would indeed make records even more powerful as they are already.

Edit: Updated for Spring4D 1.2.1 syntax.