2016-06-19 82 views
5

Ho questo codice (ho bisogno di aggiungere oggetto stringa a TStringList):È necessario liberare un BSTR (WideString) allocato con SysAllocString?

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

E poi leggerlo:

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

mi chiedevo se il sistema si prenderà cura di BSTR che era assegnato con SysAllocString. o devo chiamare SysFreeString? non è chiaro dalla documentazione.

Ora, se il sistema lo disalloca, c'è un modo per dimostrarlo?

P.S: Infatti, si tratta di suffucient chiamare:

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

Senza usare SysAllocString. (e non riesco a capire come funziona)

risposta

6

Qui la riga seguente assegna un nuovo BSTR e riempie il puntatore al puntatore SL.Objects[].

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

Così il seguente sarà perdere definitivamente la memoria:

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

Qui sarà assegnata una nuova WS esempio , quindi l'istanza BSTR puntato da SL.Objects[0] non sarà rilasciato.

e le seguenti funzioni per caso:

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

La memoria puntato dal buffer di memoria è PWideChar(WS) contenente ancora al precedente WS: WideString istanza. Così può funzionare ... fino a quando il buffer non viene riutilizzato e sostituito da altri dati e viene restituito un altro testo o si verifica un GPF casuale.

In base al consiglio: non imbrogliare mai il sistema di tipo Delphi, memorizzando qualcosa di diverso da uno TObject in una variabile immessa come TObject ... a meno che non si sappia cosa si sta facendo. Non giocare con i puntatori finché non sai cosa sono e come funzionano.

Non vedo alcun vantaggio di memorizzare uno WideString all'interno di una voce TStrings.Object[]!Modifica la struttura dei dati: crea un vero class, memorizzando la stringa. Allora tutto sarebbe chiaro e pulito:

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 

Il piccolo sovraccarico di assegnazione un'istanza class è trascurabile nei confronti di un'allocazione stringa di BSTR, quello che posso dirvi. E il tuo codice sarebbe definitivamente più pulito e più facile da mantenere/evolvere.

+0

Speravo che il sistema gestisse la distruzione dell'oggetto "WideString". se uso una struttura di classe ho bisogno di liberare manualmente ogni oggetto (non c'è OwnsObject in D7 per TStringList). Non sono ancora sicuro se I ** deve ** stringhe libere che sono allocate con 'SysAllocString' o il sistema può occuparsene per me? ... – zig

+0

Sì, ** devi ** stringhe BSTR gratuite allocate da SysAllocString. –

2

Delphi libera la WideString non appena esce dall'oscilloscopio.
Perché WideString è un tipo gestito.
Tuttavia, se lanci il widestring su PWideChar, Delphi non conta come un riferimento e quindi distruggerà la stringa non appena la funzione si chiude, anche se c'è ancora un riferimento ad essa.

Questo è male perché ora hai un puntatore penzolante. Questo è il motivo per cui è necessario SysAllocString.

Quello che SysAllocString fa è una copia della stringa inserita. Questa copia non è gestita, quindi dovrai distruggerlo tu stesso usando SysFreeString.