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