Search code examples
memory-managementconstructordelphi-xe2smart-pointers

How to use smart pointer on default constructor


So, once again I am learning new things and I came across Smart Pointers. I had code

procedure TForm3.BitBtn1Click(Sender: TObject);
var
  _StringList: ISmartPointer<TStringList>;
begin
  _StringList := TSmartPointer<TStringList>.Create(TStringList.Create);
end;

As you see variable declaration is kinda odd, and simplification is needed. I came across another solution

procedure TForm3.btnDelphiClick(Sender: TObject);
var
  _StringList: TStringList;
begin
  _StringList := SmartGuard.SmartGuard<TStringList>(TStringList.Create(False));
end;

Sadly, it does not work with parameterless constructor

procedure TForm3.btnDelphiClick(Sender: TObject);
var
  _StringList: TStringList;
begin
  _StringList := SmartGuard.SmartGuard<TStringList>(TStringList.Create);
end;

[dcc32 Error] Main.pas(47): E2089 Invalid typecast

Am I out of luck here? P.S. I know some of you would argue I should stick to try..finally block, but this is out of curiosity.

unit SmartGuard;

interface

type
  IGuard = interface
  ['{CE522D5D-41DE-4C6F-BC84-912C2AEF66B3}']
  end;

  TGuard = class(TInterfacedObject, IGuard)
  private
    FObject: TObject;
  public
    constructor Create(AObject: TObject);
    destructor Destroy; override;
  end;

  SmartGuard<T: class> = record
  private
    FGuard: IGuard;
    FGuardedObject: T;
  public
    class operator Implicit(GuardedObject: T): SmartGuard<T>;
    class operator Implicit(Guard: SmartGuard<T>): T;
  end;

implementation

uses
  {Delphi}
  System.SysUtils
  {Project}
  ;

constructor TGuard.Create(AObject: TObject);
begin
  FObject := AObject;
end;

destructor TGuard.Destroy;
begin
  FObject.Free;
  inherited;
end;

{ SmartGuard }

class operator SmartGuard<T>.Implicit(GuardedObject: T): SmartGuard<T>;
begin
  Result.FGuard := TGuard.Create(GuardedObject);
  Result.FGuardedObject := GuardedObject;
end;

class operator SmartGuard<T>.Implicit(Guard: SmartGuard<T>): T;
begin
  Result := Guard.FGuardedObject;
end;

end.

I would love to find a solution that would not require additional "method" calling as in here https://github.com/marcocantu/DelphiSessions/blob/master/DelphiLanguageCodeRage2018/02_SmartPointers/SmartPointerClass.pas e.g. _StringList.Value.Add('foo'); and "special" brackets e.g. _StringList := TSmartPointer<TStringList>.Create(TStringList.Create)();


Solution

  • The compiler needs help disambiguating

    TStringList.Create
    

    The compiler doesn't know whether this is a reference to a method, or a call to the method.

    Disambiguate by adding parens to indicate that it is a call.

    _StringList := SmartGuard.SmartGuard<TStringList>(TStringList.Create());