不应该在对象引用设置为nil时调用Free每次调用时都会抛出一个访问冲突吗?

Gee*_*ten 7 delphi delphi-xe

我从该单元获取访问权限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;
Run Code Online (Sandbox Code Playgroud)

但我看到这样的结构(首先分配Nil,然后是免费)DBXCommon.pas.这是一些我不知道的构造,或者每次调用这段代码这是否真的导致访问冲突?

Rob*_*edy 15

调用Freenull引用始终是安全的.去看看执行情况TObject.Free,看看为什么.

此代码是工厂函数的示例.它的工作是创建一个类的新实例,但是如果它失败了,它需要确保它在抛出异常时不会泄漏半创建的实例,因此它会调用Free.当它确定它会成功时,它会将结果的所有权转移给调用者.它仍然会调用Free,但如果它已经转移了所有权,那么它最终会调用Free一个空引用,并且没有任何损害.此代码转移所有权:

Result := Connection;
Connection := nil;
Run Code Online (Sandbox Code Playgroud)

顺便会写一个工厂函数将废除独立的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;
Run Code Online (Sandbox Code Playgroud)

这具有相同的效果.

  • +1这是编写返回新对象的函数的惯用方法 (2认同)

ain*_*ain 6

它是安全的调用Freenil的参考,因为它的实施检查Self <> nil之前调用Destroy.见艾伦·鲍尔在解释Embarcadero的论坛为什么TObject.Free被引入.我在这里只包括相关的引用:

在TObject上引入非虚拟Free方法的唯一原因是在析构函数中使用它作为简单的简写:

if FField <> nil then
  FField.Destroy;
Run Code Online (Sandbox Code Playgroud)

  • 德尔福历史的+1点投入:-) (2认同)
  • 现在还没有吸取教训吗?人们应该停止链接到 Embarcadero 网页。他们只在那里呆了 2-3 年。然后……噗。走了 :) :) (2认同)