我必须释放使用 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。
我有这段代码(我需要将字符串对象添加到 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。