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

时间:2016-06-19 17:45:22

标签: delphi memory-management delphi-7

我有这个代码(我需要将字符串对象添加到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。 (而且我无法理解它是如何工作的)

2 个答案:

答案 0 :(得分:6)

以下行确实分配了一个新的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字符串分配方面是可以忽略的。而且您的代码最终会更清晰,更易于维护/发展。

答案 1 :(得分:2)

Delphi将在超出范围时立即释放WideString 因为WideString是托管类型 但是,如果将宽带字符串转换为PWideChar,则Delphi不会将其作为引用计数,因此一旦函数退出就会销毁该字符串,即使仍有对它的引用。

这很糟糕,因为现在你有一个悬垂的指针。这就是您需要SysAllocString的原因。

SysFreeString做的是复制您输入的字符串。此副本不受管理,因此您需要使用GroupedByEndoAndCstage <- PragueSubset %>% group_by(EndoID,Cstage) %>% summarise(Sum = sum(NumBx)) 自行销毁它。