Some bullet points:
if Assigned(Obj) then Obj.Free is redundant, you can just call Obj.Free - Free is static and can be called on nil instance and also Free has nil check within before calling destructor
constructors are allowed to raise exceptions
destructors must never raise exceptions (without handling them within with try...except)
destructors can be called on half constructed instance (if the constructor fails, destructor chain will be automatically called) and must be able to handle such scenarios without causing trouble - raising exceptions
when constructor fails assignment to variable will never happen
local object variables are never automatically initialized and they can contain random garbage
object instance fields are always zero initialized when constructor chain is being called
Because of the above correct construction pattern is
var
LA: TRaiseOnMinus;
begin
LA := TRaiseOnMinus.Create( -2 );
try
//some code
finally
LA.Free;
end;
end;
With multiple constructors there are multiple options, but I prefer using only single try...finally because destructors must not raise exceptions, single try finally is faster and cleaner
var
LA, LB: TRaiseOnMinus;
begin
LB := nil;
LA := TRaiseOnMinus.Create( -2 );
try
LB := TRaiseOnMinus.Create( -3 );
//some code
finally
LB.Free;
LA.Free;
end;
end;
Correct constructor and destructor for your class would be:
constructor TRaiseOnMinus.Create( AParam : Integer );
begin
inherited;
if AParam < 0 then
raise Exception.Create( 'Bum' );
FMyList := TStringList.Create;
end;
destructor TRaiseOnMinus.Destroy;
begin
FMyList.Free;
inherited;
end;
Only if you need to do some additional work with FMyList in destructor, then you must check it for nil before using it. In such cases you can find call to Free within the same check, but not because it wouldn't work outside.
destructor TRaiseOnMinus.Destroy;
begin
if Assigned(FMyList) then
begin
FMyList.DoSomethingImportant;
FMyList.Free;
end;
inherited;
end;