我必须释放使用 SysAllocString 分配的 BSTR (WideString) 吗?

Must I free a BSTR (WideString) allocated with SysAllocString?

我有这段代码(我需要将字符串对象添加到 TStringList):

var
  WS: WideString;
begin
  WS := 'allocated string';
  SL.AddObject('my string', TObject(SysAllocString(PWideChar(WS))));

稍后阅读:

var
  WS: WideString;
begin
  WS := PWideChar(SL.Objects[0]);
  ShowMessage(WS);

我想知道系统是否会处理分配给 SysAllocString 的 BSTR。还是我必须打电话给 SysFreeString?从文档中不清楚。

现在,如果系统确实取消分配它,有什么办法可以证明它确实如此吗?

P.S: 事实上,调用就足够了:

SL.AddObject('my string', TObject(PWideChar(WS)));

不使用 SysAllocString。 (而且我不明白它是如何工作的)

Delphi 将在 WideString 超出范围后立即释放它。
因为 WideString 是托管类型。
但是,如果您将 widestring 转换为 PWideChar,Delphi 不会将其视为引用,因此会在函数退出后立即销毁该字符串,即使仍然存在对它的引用。

这很糟糕,因为现在您有一个悬挂指针。这就是为什么你需要 SysAllocString

SysAllocString 所做的是复制您输入的字符串。此副本不受管理,因此您需要使用 SysFreeString.

自行销毁它

下面一行确实分配了一个新的 BSTR 并将其指针填充到 SL.Objects[] 指针。

  SL.AddObject('my string', TObject(SysAllocString(PWideChar(WS))));

所以下面的明确地泄漏内存:

var
  WS: WideString;
begin
  WS := PWideChar(SL.Objects[0]);

这里会分配一个new WS实例,所以你的SL.Objects[0]指向的BSTR实例不会被释放。

下面是偶然的:

SL.AddObject('my string', TObject(PWideChar(WS)));

PWideChar(WS) 内存缓冲区指向的内存仍然包含前一个 WS: WideString 实例。这可能会起作用...直到缓冲区被其他数据重新使用和覆盖,并且返回另一个文本,或者出现随机 GPF。

建议:永远不要欺骗 Delphi 类型系统,在类型为 TObject 的变量中存储 TObject 以外的东西......除非你知道你在做什么。在了解指针是什么以及它们的工作原理之前,不要玩指针。

我看不出将 WideString 存储在 TStrings.Object[] 条目中有任何好处!更改您的数据结构:创建一个真正的 class,存储您的字符串。那么一切都会变得清晰干净:

type
  TMyStoreWS = class
  protected
    fText: WideString;
  public
    constructor Create(const aText: WideString); virtual;
    property Text: WideString read fText write fText;
  end;

constructor TMyStoreWS.Create(const aText: WideString);
begin
  inherited Create;
  fText := aText;
end;

...
SL.AddObject('my string', TMyStoreWS.Create(aText)); // clean
...
ShowMessage(SL.Objects[0].Text); // clean
SL.Objects[0].Free; // don't forget to release 

分配 class 实例的小开销对于 BSTR 字符串分配来说可以忽略不计,我可以告诉你。而且您的代码肯定会更清晰,更容易 maintain/evolve。