C'è una sezione su floating references nel manuale di riferimento di GObject che va un po 'più in dettaglio. I riferimenti fluttuanti possono sembrare un po 'oscuri, ma sono davvero molto utili per C, quindi prendere qualche minuto per capirli davvero è una buona idea.
Suppongo che tu capisca come funziona il conteggio dei riferimenti - se non c'è molta documentazione là fuori, prenditi qualche minuto e leggi quanto prima.
Prima di tutto, vediamo cosa accadrebbe nell'esempio se g_variant_new_boolean
restituisse un riferimento regolare. Quando si ottiene il valore per la prima volta, il conteggio dei riferimenti sarà 1. Quando lo si passa a g_variant_new
, g_variant_new
aumenterà il conteggio dei riferimenti a 2. Ad un certo punto presumo che si disponga di another_v
, a quel punto il conteggio dei riferimenti per a_v
scenderà a 1 ... ma ricorda, la memoria non viene rilasciata fino a quando il conteggio dei riferimenti raggiunge 0.
Per aggirare questo hai due opzioni.Il primo è quello di rendere g_variant_new
rubare il riferimento del chiamante, che in sostanza fa schifo come soluzione. Dacci via il tuo riferimento quando chiami g_variant_new
(o qualsiasi funzione simile), quindi in futuro dovrai rifare manualmente a_v
ogni volta che vuoi passarlo a qualcos'altro.
L'altra opzione è quella di sfilarlo manualmente una volta terminato. Non è la fine del mondo, ma è facile dimenticare di fare o sbagliare (ad esempio dimenticando di slegarlo in un percorso di errore).
Ciò che invece GVariant restituisce è un riferimento "mobile". Il modo più semplice per pensarci (IMHO) è che la prima volta che viene chiamato g_variant_ref
non fa veramente niente, semplicemente "affonda" il riferimento fluttuante. Il conteggio dei riferimenti va da 1 a 1. Successive chiamate a g_variant_ref
, tuttavia, aumenterà il conteggio dei riferimenti.
Ora vediamo cosa succede realmente con il tuo esempio. g_variant_new_boolean
restituisce un riferimento mobile. Si passa quindi a g_variant_new
, che chiama g_variant_ref
, che affonda il riferimento mobile. Il conteggio dei riferimenti ora è 1, e quando il conteggio di another_v
raggiunge il numero 0 a_v
, il conto verrà decrementato, in questo caso si raggiunge 0 e tutto sarà liberato. Non c'è bisogno che tu chiami il numero g_variant_unref
.
La parte interessante di riferimenti galleggiante, però, è quello che succede con qualcosa di simile:
GVariant *a_v = g_variant_new_boolean(TRUE);
GVariant *another_v = g_variant_new("v", a_v);
GVariant *yet_another_v = g_variant_new("v", a_v);
Quando g_variant_new
si chiama la seconda volta a_v
s' refcount incrementerà di nuovo (a 2). Non è necessario chiamare lo g_variant_ref
prima di passare a_v
a g_variant_new
una seconda volta: la prima chiamata appare come la prima e la coerenza è una funzionalità molto bella in un'API.
A questo punto è probabilmente ovvio, ma sì, è necessario chiamare g_variant_unref
su another_v
(e, in quest'ultimo esempio, yet_another_v
).
Ottima spiegazione. Grazie per aver dedicato del tempo per spiegarlo in dettaglio. – kaylum
Puoi spiegarlo per favore "e quando il conteggio di another_v raggiunge 0 il conteggio di a_v sarà decrementato". Quando il conto di un'altra_v arriverà a 0? –
Ogni qualvolta un altro codice chiama 'g_variant_unref (another_v)'. Fondamentalmente, quando il contenitore ('another_v') viene distrutto, decrementerà anche il conteggio di riferimento di a_v'. Dal momento che quel conto è 1 prima della chiamata, decrementandolo lo ridurrà a 0, il che significa che sarà liberato. La rilettura del terzo paragrafo (che descrive cosa succede per ** non ** - riferimenti mobili) potrebbe essere utile. – nemequ