2016-06-19 1 views
5

J'ai ce code (je dois ajouter objet chaîne à TStringList):Dois-je libérer un BSTR (WideString) alloué avec SysAllocString?

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

Et plus tard lire:

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

Je me demandais si le système se chargera de l'BSTR qui était attribué avec SysAllocString. ou dois-je appeler SysFreeString? ce n'est pas clair à partir de la documentation.

Maintenant, si le système le désaffecte, est-il possible de le prouver?

P.S: Enfait, il est suffucient appeler:

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

Sans utiliser SysAllocString. (et je ne peux pas comprendre comment cela fonctionne)

Répondre

6

Ici la ligne suivante alloue un nouveau BSTR et remplit son pointeur vers le pointeur SL.Objects[].

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

Ainsi, le va suivant une fuite définitivement mémoire:

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

Voici une instance nouvelle WS sera alloué, de sorte que votre instance BSTR pointée par SL.Objects[0] ne sera pas publié.

Et ce qui suit fonctionne par hasard:

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

La mémoire pointée par la mémoire tampon est PWideChar(WS) contient encore à l'WS: WideString instance précédente. Cela peut donc fonctionner ... jusqu'à ce que le tampon soit réutilisé et remplacé par d'autres données, et qu'un autre texte soit renvoyé, ou qu'un GPF aléatoire se produise. Par conseil: ne jamais tricher le système de type Delphi, en stockant autre chose qu'un TObject dans une variable tapée TObject ... sauf si vous savez ce que vous faites. Ne jouez pas avec des pointeurs avant de savoir ce qu'ils sont et comment ils fonctionnent.

Je ne vois aucun avantage à stocker un WideString dans une entrée TStrings.Object[]!Changez votre structure de données: créez un vrai class, en stockant votre chaîne. Ensuite, tout serait clair et propre:

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 

La petite surcharge d'allocation d'une instance class est négligeable en ce qui concerne une allocation de chaîne BSTR, je peux vous dire. Et votre code serait définitivement plus propre et plus facile à entretenir/évoluer.

+0

J'espérais laisser le système gérer la destruction de "l'objet" WideString. si j'utilise une structure de classe, j'ai besoin de libérer manuellement chaque objet (il n'y a pas d'OwnsObject dans D7 pour TStringList). Je ne suis toujours pas sûr si je dois ** libérer ** les chaînes qui sont allouées avec 'SysAllocString' ou le système peut s'occuper de ça pour moi? ... – zig

+0

Oui, vous devez ** libérer ** des chaînes BSTR allouées par SysAllocString. –

2

Delphi va libérer le WideString dès qu'il sort de la portée.
Parce que WideString est un type géré.
Cependant, si vous transtypez la chaîne large en PWideChar, Delphi ne compte pas comme référence et détruira donc la chaîne dès que la fonction sera terminée, même s'il y a toujours une référence.

C'est mauvais parce que maintenant vous avez un pointeur qui pend. C'est pourquoi vous avez besoin de SysAllocString.

Ce que SysAllocString fait est de faire une copie de la chaîne que vous alimentez. Cette copie n'est pas gérée, vous devrez donc la détruire vous-même en utilisant SysFreeString.