我从单位DBXCommon.pas
(在Delphi XE中)获取访问冲突。当我查看代码时,我会看到以下内容(在感叹号处):
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;
但是我在DBXCommon.pas
中看到了更像这样的构造(首先分配Nil,然后是免费)。这是一些我不知道的构造,或者这是否真的导致访问冲突每次这段代码被调用?
答案 0 :(得分:15)
在空引用上调用Free
始终是安全的。请查看TObject.Free
的实现,了解原因。
此代码是工厂功能的示例。它的工作是创建一个类的新实例,但是如果它失败了,它需要确保它在抛出异常时不会泄漏半创建的实例,因此它调用Free
。当它确定它会成功时,它会将结果的所有权转移给调用者。它仍然会调用Free
,但如果它已经转移了所有权,那么它最终会在空引用上调用Free
,并且没有任何损害。此代码转移了所有权:
Result := Connection;
Connection := nil;
I 编写工厂函数的方式将取消单独的Connection
变量。我会直接在Result
中构造结果,但是如果有异常则释放它,如下所示:
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;
这具有相同的效果。
答案 1 :(得分:6)
可以安全地在Free
引用上调用nil
,因为它在调用Self <> nil
之前对Destroy
进行了实施检查。请参阅Embarcadero forum中的Allen Bauer解释为什么引入TObject.Free
。我在这里只包括相关的引用:
在TObject上引入非虚拟Free方法的唯一原因是在析构函数中使用它作为简单的简写:
if FField <> nil then
FField.Destroy;
答案 2 :(得分:4)
TObject.Free
基本上实现为if Self <> nil then Destroy
,因此上面的代码不应引发任何异常。