Did you know g_clear_object/pointer() ?

g_clear_object() has been in glib since 2.28, and now g_clear_pointer() has landed in glib master (see bug #674634).
Their typical usage is to implement GObject::dispose, or “goto out” pattern, previously you would write:

void my_dispose (GObject *obj)
{
  MyObject *self = (MyObject *) obj;
  if (self->priv->object != NULL)
    {
      g_object_unref (self->priv->object);
      self->priv->object = NULL;
    }
  if (self->priv->hash != NULL)
    {
      g_hash_table_unref (self->priv->hash);
      self->priv->my_hash = NULL;
    }
  etc...
}

or:

void some_func ()
{
  GHashTable *tmp = NULL;

  ...
  if (error)
    goto out;

  tmp = g_hash_table_new();
  ...

out:
  if (tmp != NULL)
    g_hash_table_unref (tmp);
}

But now those becomes:

void my_dispose (GObject *obj)
{
  MyObject *self = (MyObject *) obj;

  g_clear_object (&self->priv->object);
  g_clear_pointer (&self->priv->hash, g_hash_table_unref);
  etc...
}

or:

void some_func ()
{
  GHashTable *tmp = NULL;

  ...
  if (error)
    goto out;

  tmp = g_hash_table_new();
  ...

out:
  g_clear_pointer (&tmp, g_hash_table_unref);
}

As extra bonus, g_clear_object() and g_clear_pointer() are thread-safe. That means that 2 threads can clear the same pointer at the same time and it will be freed only once. I’ve heard some code needs thread-safe dispose…

Thanks to Simon McVittie for the original idea in telepathy-glib where we had tp_clear_object/pointer for years.

4 thoughts on “Did you know g_clear_object/pointer() ?”

  1. So, *every* single free call does a bus-locking cmpxchg operation.
    This isn’t exactly free. Are you sure this is a good idea?

  2. @alexl: as you said on the bug, if you destroy with _unref() it’s going to use atomics anyway. But I can understand it’s not optimal to use with _free(). I personally don’t care about the thread-safe aspect, but that’s how g_clear_object() has been made since 2.28…

Leave a Reply

Your email address will not be published. Required fields are marked *