I have this code (I need to add string object to TStringList):
var
WS: WideString;
begin
WS := 'allocated string';
SL.AddObject('my string', TObject(SysAllocString(PWideChar(WS))));
And later read it:
var
WS: WideString;
begin
WS := PWideChar(SL.Objects[0]);
ShowMessage(WS);
I was wondering if the system will take care of the BSTR which was allocated with SysAllocString
. or must I call SysFreeString
? it's not clear from the documentation.
Now, If the system does De-allocates it, is there any way to prove it does?
P.S: Infact, it is suffucient to call:
SL.AddObject('my string', TObject(PWideChar(WS)));
Without using SysAllocString
. (and I can't understand how it works)
Here the following line does allocate a new BSTR
and fill its pointer to the SL.Objects[]
pointer.
SL.AddObject('my string', TObject(SysAllocString(PWideChar(WS))));
So the following will definitively leak memory:
var
WS: WideString;
begin
WS := PWideChar(SL.Objects[0]);
Here a new WS instance will be allocated, so your BSTR instance pointed by SL.Objects[0]
won't be released.
And the following is working by chance:
SL.AddObject('my string', TObject(PWideChar(WS)));
The memory pointed by the PWideChar(WS)
memory buffer is still containing to the previous WS: WideString
instance. So is may work... until the buffer is re-used and overriden by some other data, and another text is returned, or a random GPF occurs.
By advice: never cheat the Delphi type system, storing something else than a TObject
in a variable typed as TObject
... unless you know what you are doing. Don't play with pointers until you know what they are and how they work.
I do not see any benefit of storing a WideString
within a TStrings.Object[]
entry! Change your data structure: create a true class
, storing your string. Then everything would be clear and clean:
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
The small overhead of allocating a class
instance is negligeable in regard to a BSTR
string allocation, I can tell you. And your code would definitively be cleaner and easier to maintain/evolve.
Delphi will free the WideString as soon as it goes out of scope.
Because WideString is a managed type.
However if you cast the widestring to a PWideChar, Delphi does not count that as a reference and will thus destroy the string as soon as the function exits, even though there is still a reference to it.
That's bad because now you've got a dangling pointer. This is why you need SysAllocString
.
What SysAllocString
does is make a copy of the string you feed in. This copy is not managed, so you'll need to destroy it yourself using SysFreeString
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With