Delphi tstringlist.free删除结果[重复]

ve7v8dk2  于 2023-01-05  发布在  其他
关注(0)|答案(2)|浏览(161)
    • 此问题在此处已有答案**:

How do i return an object from a function in Delphi without causing Access Violation?(10个答案)
2天前关闭。
好吧,这个我不明白。

path:=tstringlist.create;
   //load up the path with stuff
   Result := path;
   path.free;
   exit;

I would have thought that result would actually equal the path but it apparently doesn't. If I remove path.free from the code above, the result works as it should and it = the path tstringlist but I get a memory leak. When I put path.free in there, the result becomes empty. I understand the memory leak but how is result getting erased if I free the path AFTER I make it := ????
是的,上面的代码在多个for循环中,这就是我使用exit的原因。我试过break和try finally,但也没有成功。

wnavrhmk

wnavrhmk1#

让我重新表述变量和类名,并添加一些注解:

function MyNewHouse(): TStringList;
var
  NewAddress: TStringList;
begin
  // Construct a house with walls, windows, doors and a roof. Those
  // are the properties and methods that we're able to use later.
  NewAddress := House.Create();

  // ...fill the house with content, using our walls, windows, doors...

  // Only copy the new house's address, not the house in its entirety.
  // And certainly not its content.
  Result := NewAddress;

  // Demolish/Tear down the house, which can only be made once. When
  // the house is demolished, you can neither access it, nor tear it
  // down anew. However, the address is still somewhat "valid". While
  // everything but the spot where it once existed is gone.
  NewAddress.Free();

  Exit;
end;

每当你赋值class类型的变量(比如TObjectTStringListTForm)时,你只是复制了它的地址,而不是它的全部内容。

// Instead of only "Result := NewAddress;"
  Result.Assign( NewAddress );

That复制其全部内容。这个方法存在于许多类中,对于每个不同的类,“复制其内容”可能意味着不同的事情,就像你可能想复制一个TStringList的项目,但不一定是它的其他设置。但如果你想这样做,你应该已经在你的例子中使用Result.Items := NewAddress.Items了...

uqdfh47h

uqdfh47h2#

包含path.freeResult变为空的原因是Result只是对path的引用。调用path.free时,将释放该路径占用的内存,这将使对该内存的引用无效。释放path后尝试访问Result时,将尝试访问无效内存。这可能导致不确定的行为。
您需要在函数外部释放返回的TStringList,应按如下所示修改函数:

function getPath: TStringList;
begin
  Result := tstringlist.create;
  //load up the path with stuff
end;

// usage:
var
  path: TStringList;
begin
  path := getPath;
  try
    // use path here
  finally
    path.Free;
  end;
end;

这样,返回的TStringList在函数内部创建,并作为引用传递给调用方。调用方负责在不再需要TStringList时通过调用Free来释放它。这被称为“资源获取即初始化”(RAII),是 Delphi 中管理资源(如动态分配的对象)的常见模式。
通过使用此模式,可以确保始终正确释放TStringList并避免潜在的内存泄漏。
更高级的技巧(XE2+):

type
  IScope<T: class> = interface
  private
    function GetIt: T;
  public
    property It: T read GetIt;
  end;

  TScope<T: class> = class(TInterfacedObject, IScope<T>)
  private
    FValue: T;
  public
    constructor Create(const AValue: T);
    destructor Destroy; override;
    function GetIt: T;
  end;

constructor TScope<T>.Create(const AValue: T);
begin
  inherited Create;
  FValue := AValue;
end;

destructor TScope<T>.Destroy;
begin
  FValue.Free;
  inherited;
end;

function TScope<T>.GetIt: T;
begin
  Result := FValue;
end;

function getPath: IScope<TStringList>;
var
  path: TStringList;
begin
  path := tstringlist.create;
  //load up the path with stuff
  Result := TScope<TStringList>.Create(path);
end;

// usage:
var
  path: TStringList;
begin
  path := getPath.It;
  // use path here
end; // auto-free here

相关问题