wiki:GRefPtr

Version 4 (modified by Adrian Perez de Castro, 10 years ago) (diff)

Reword some parts, add when-to-use section

Reference counting with GRefPtr<T>

In the GLib/GObject/GTK+ 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:

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 doWithWidget(GtkWidget* widget) {
    GRefPtr<GtkWidget> widgetLocal1 = widget;
    GRefPtr<GtkWidget> widgetLocal2 = widgetLocal1;
}

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);
    }