Version 10 (modified by 6 years ago) ( diff ) | ,
---|
Reference counting with GRefPtr<T>
In the GObject object model, instances are reference-counted. To ease handling those in !WebKitGTK+ code, the GRefPtr<T>
template is provided. It keeps a pointer to a reference-counted and takes care of properly increasing and decreasing the reference counts for object being held. Helper functions are provided as well (e.g. adoptGRef()
).
Sources:
See: https://www.webkit.org/coding/RefPtr.html
Usage
Creation
Creating a GRefPtr<T>
initializes it to nullptr
:
GRefPtr<GMainContext> context; // Check always succeeds, nullptr is the default value. ASSERT(!context);
Destruction
When a GRefPtr<T>
goes is destroyed, it decreases the reference count of the object it holds.
Adopting a reference
Sometimes it is desirable to store a pointer in a GRefPtr
without increasing the reference counter. The main use case is assigning a newly created instance to a GRefPtr
: the newly created instance already has a reference count of one and assigning it to a GRefPtr
would increase the reference count to two, which would be incorrect (and very likely would cause a leak). To avoid this, the adoptGRef()
helper function is provided. This function creates a GRefPtr
without increasing the reference counter of the object it holds. This is incorrect:
// Incorrect: The created object has *two* references, even // when referenced only from the “context” variable. GRefPtr<GMainContext> context = g_main_context_new();
And this is correct:
// Correct: The newly created object has only one reference GRefPtr<GMainContext> context = adoptGRef(g_main_context_new());
Assignment
Assigning to a GRefPtr
increases the reference count for the pointer being assigned. Both raw pointers and other GRefPtr
instances can be assigned:
void doWithData(GByteArray* data) { GRefPtr<GByteArray> dataLocal1 = data; GRefPtr<GByteArray> dataLocal2 = dataLocal1; }
Raw pointer
To obtain the raw pointer use the get()
method. This is typically used when calling functions from support libraries used by the port (GLib, GTK+, etc). For example:
void show(GRefPtr<GtkWidget>& widget) { gtk_widget_show_all(widget.get()); }
Floating references
Some types have a floating reference when created, for example GtkWidget
and derived types and GVariant
. Most of the time it is incorrect to use adoptGRef()
on newly created instances of types which use floating references: the floating reference has to be converted on a full reference. Assigning to a GRefPtr
will convert the floating reference to a full reference.
Incorrect usage:
GRefPtr<GVariant> variant = adoptGRef(g_variant_new("s", "Incorrect usage"));
Correct usage:
GRefPtr<GVariant> variant = g_variant_new("s", "Floating reference is sank");
When to use
In the following cases it is recommended to use GRefPtr<T>
:
- When holding references as attribute members of instances. Note that this also makes it easier to write accessor methods at the API level, as the refing/unrefing of objects is done automatically:
struct FooPrivate { GRefPtr<GVariant> someData; }; // Public API method void foo_set_data(Foo* foo, GVariant* data) { FooPrivate* priv = foo_get_private(foo); // Takes care of unrefing the previously held object // and also refing the passed object. priv->someData = data; }
- When using local references to objects which should be freed/unrefed when the local variable goes out of scope:
void doSomethingWithALocalReference() { GRefPtr<GVariant> temporaryData = g_variant_new("s", "SpamAndEggs"); // Use “temporaryData” as needed, it will be freed automatically // when the variable goes out of scope at the end of the function }
In the following cases it is not recommended to use GRefPtr<T>
:
- When creating an initially unowned object —that is, it has a floating reference— which is going to be passed to another function/object that will consume the floating reference. For example:
GVariant* createData(int value) { // This function does not use the new value; the caller // is responsible of consuming the floating reference. return g_variant_new("(si)", "int", value); } void someOtherCode() { // Picks the GVariant created by the above function and // grabs the floating reference, to make sure intData is // freed when it goes out of scope. GRefPtr<GVariant> intData = createData(42); useIntData(intData); }