Should you call Free on the object link given as nil to throw an access violation each time it is called?

I get access violations from a DBXCommon.pas block (in Delphi XE). When I look at the code, I see things like the following (on exclamation points):

 function TDBXConnectionFactory.GetConnection(const DBXContext: TDBXContext; const ConnectionProperties: TDBXProperties): TDBXConnection; var ConnectionBuilder: TDBXConnectionBuilder; DelegatePath: TDBXDelegateItem; Connection: TDBXConnection; CombinedProperties: TDBXProperties; begin //... ConnectionBuilder := TDBXConnectionBuilder.Create; Connection := nil; try //..lots of setting ConnectionBuilder properties ConnectionBuilder.FInputPassword := CombinedProperties[TDBXPropertyNames.Password]; Connection := ConnectionBuilder.CreateConnection; Connection.Open; Result := Connection; !! Connection := nil; finally !! Connection.Free; ConnectionBuilder.Free; end; end; 

But I see such constructs (first assign Nil, then Free) much more in DBXCommon.pas . Is this some kind of construct that I don't know, or does it really cause an access violation every time this piece of code gets called?

+7
source share
3 answers

Calling Free on a null link is always safe. Go to the TObject.Free implementation to see why.

This code is an example of a factory function. Its task is to create a new instance of the class, but if it fails, it needs to make sure that it does not leak the semi-delivered instance when it throws an exception, so it throws Free . When he is sure that it will be successful, it transfers ownership of the result to the caller. It still calls Free , but if it has already transferred ownership, it ends the Free call with a null reference, and no harm is done. This code transfers ownership:

 Result := Connection; Connection := nil; 

The way I write the factory function will delete a separate Connection variable. I would build the result directly in Result , but release it if an exception occurred, for example:

 function TDBXConnectionFactory.GetConnection(const DBXContext: TDBXContext; const ConnectionProperties: TDBXProperties): TDBXConnection; var ConnectionBuilder: TDBXConnectionBuilder; DelegatePath: TDBXDelegateItem; Connection: TDBXConnection; CombinedProperties: TDBXProperties; begin //... ConnectionBuilder := TDBXConnectionBuilder.Create; try //..lots of setting ConnectionBuilder properties ConnectionBuilder.FInputPassword := CombinedProperties[TDBXPropertyNames.Password]; Result := ConnectionBuilder.CreateConnection; try Result.Open; except Result.Free; raise; end; finally ConnectionBuilder.Free; end; end; 

This has the same effect.

+15
source

It is safe to call the Free reference on nil , because it performs a Self <> nil check before calling Destroy . See Allen Bauer's explanation in the Embarcadero forum why TObject.Free was introduced. I include only the relevant quote here:

The only reason for introducing the non-virtual free method in TObject was used in destructors as a simple shorthand for:

 if FField <> nil then FField.Destroy; 
+6
source

TObject.Free is basically implemented as if Self <> nil then Destroy , so the code above should not throw any exceptions.

+4
source

All Articles