Avoid G_TYPE_INSTANCE_GET_PRIVATE() in GObjects

When developing GObjects in Glib/GObject framework, it is usual to have a structure defined in the source file with all the private members of the object. Doing this, the internals of the object are not published in its API, so that no other module outside can modify them without using the defined GObject methods.

There are several ways to achieve this, and one of them is the recommended one in GObject’s tutorial [1], which uses the G_TYPE_INSTANCE_GET_PRIVATE [2] macro to get the glib-instantiated private structure. This private structure, allocated for each instance of the object, is specified in the Class initialization function with g_type_class_add_private(), and allocated every time a new GObject instance is created.

Usually, you will have a macro for your specific GObject which will call G_TYPE_INSTANCE_GET_PRIVATE:

#define MY_GOBJECT_GET_PRIVATE(o) \
    (G_TYPE_INSTANCE_GET_PRIVATE((o), MY_GOBJECT_TYPE, MyGObjectPrivate))


This seems a good way of doing it, and quite simple to use. Glib will take care of allocating and deallocating that private structure for us… so why avoid it?

Well… if you ever tried to run Valgrind’s callgrind tool to measure how much time your program spends in a given function, you will see the reason. Other people already did that and published results on the web, so go and check them [3] or just try it with your application:

$> valgrind --tool=callgrind /usr/local/bin/your_program</span


Now, an easy way of getting the same result, with a little bit more of work but achieving the best performance, is just using an opaque pointer in the GObject’s public structure and define, allocate and deallocate it yourself in the source file (so also can be treated as private, as the users of the API don’t know the internals of the structure).

These are the basic changes you need to do to avoid calling G_TYPE_INSTANCE_GET_PRIVATE():

**** In the HEADER of the GObject, when the struct defining the Object is specified, add a “gpointer priv” variable.

struct _MyGObject
{
    /** Parent object */
    GObject parent;
    /** Private data pointer */
    gpointer priv;
}


**** Then, in the SOURCE of the GObject, modify the GET_PRIVATE macro so that instead of doing the standard GObject lookup for the correct type, we just get the opaque “priv” pointer defined in the header, and we cast it to the correct type.

#define MY_GOBJECT_GET_PRIVATE(o) \
    ((MyGObjectPrivate *)((MY_GOBJECT(o))->priv))


**** As we won’t use the automatic allocation of the Private data structure, we need to allocate it ourselves in the _init() function.

static void
my_gobject_init(MyGObject *self)
{
    /* Allocate Private data structure */
    (MY_GOBJECT(self))->priv = \
        (MyGObjectPrivate *) g_malloc0(sizeof(MyGObjectPrivate));
    /* If correctly allocated, initialize parameters */
    if((MY_GOBJECT(self))->priv != NULL)
    {
        MyGObjectPrivate *priv = MY_GOBJECT_GET_PRIVATE(self);
        /* Initialize private data, if any */
    }
}


**** And finally, the last change is just de-allocating the structure when no more needed in the _dispose() function.

static void
my_gobject_dispose(GObject *object)
{
    MyGObject *self = (MyGObject *)object;
    MyGObjectPrivate *priv = MY_GOBJECT_GET_PRIVATE(self);
    /* Check if not NULL! To avoid calling dispose multiple times */
    if(priv != NULL)
    {
        /* Deallocate contents of the private data, if any */
        /* Deallocate private data structure */
        g_free(priv);
        /* And finally set the opaque pointer back to NULL, so that
         *  we don't deallocate it twice. */
        (MY_GOBJECT(self))->priv = NULL;
    }
}


References:

Posted on February 13, 2009, in Development and tagged , , , . Bookmark the permalink. 2 Comments.

  1. I stumbled on this blog post from some google search, hence the late comment.

    I believe your suggestion makes it ineffective in another factor – the public data and private data are not allocated sequentially anymore. With g_type_class_add_private you will get the private data in the same memory location – “Another advantage of this [g_type_class_add_private] is that is lessens memory fragmentation, as the public and private parts of the instance memory are allocated at once.”

    The solution is simple and described in (at least in) recent GObject tutorial at http://library.gnome.org/devel/gobject/unstable/howto-gobject.html (and used in many newer GObject classes implemented in gtk+ and co).
    Simply do have a private pointer in the public struct, as you have here, but also still use g_type_class_add_private. Just assign the priv pointer only once over the objects lifetime in its _init function, see the link for details.

  2. Aha, didn’t know that g_type_class_add_private() would allocate the private data in the same memory chuck as the public data of the object. In order to achieve the same result then, it’s true that is as easy as calling _get_private() at least once, and assigning the address to the opaque public pointer.

    Thanks for the info!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: