RFC: glocal - automatically freeing memory when it goes out of scope



Hi all,

I have been looking at gcc's "cleanup" attribute[1] that allows one to specify a callback that will be invoked when a variable goes out of scope. This allows one to play with automatically freeing resources.

It is very much a non-portable gccism, I am well aware, but it is nonetheless quite nice to work with in practice. It's for example extensively used in keybuk's libnih which is used as base library in Upstart where I think it makes the code more readable. Scott's particular implementation can be found here: http://bazaar.launchpad.net/~scott/libnih/trunk/view/head:/nih/alloc.h#L285

I played around with it a little, bundling stuff in a glib-gcc.h header file that I have attached to this mail. There is also an example attached as glocaltest.c. It's mostly an example and I just implemented support for strings and objects so there's not a whole lot there, yet. The interesting code snippet is:

  if (1)
    {
      glocal_object GFile *file =  g_file_new_for_path ("/tmp");
      glocal_string gchar *basename = g_file_get_basename (file);
      g_debug ("Basename is '%s'", basename);
      // look ma' no leaks!
    }

So; what say you? If there is interest I'll gladly polish it up for inclusion. There are also tonnes of other low hanging fruits like freeing other ref counted types, closing of streams, etc.

Cheers,
Mikkel

[1]: http://ohse.de/uwe/articles/gcc-attributes.html#var-cleanup
/* glib-gcc.h: gcc specific extensions to glib
 *
 * Copyright (C) 2011  Canonical Ltd
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: Mikkel Kamstrup Erlandsen <mikkel kamstrup canonical com>
 */

#include <glib.h>
#include <glib-object.h>

#ifndef __GLIB_GCC_H__
#define __GLIB_GCC_H__

#ifndef __GNUC__
  #error "This project uses non-standard GNU C extensions and requires 'gcc´ to compile."
#endif

G_BEGIN_DECLS

/**
 * glocal_string:
 * 
 * Macro declaring that a null terminated string be automatically freed when it
 * goes out of scope. For example:
 * <informalexample><programlisting>
 *   if (print_hello_world)
 *     {
 *       glocal_string gchar *str = g_strdup ("world!");
 *       g_printf ("Hello %s\n", str);
 *       // at this point 'str´ is automatically freed
 *     }
 * </programlisting></informalexample>
 * Beware that if you assign the value of the local string to some other string
 * that there is no transfer of ownership. The local variable will still be
 * freed when it goes out of scope. If you want to avoid this you can set the
 * local variable to %NULL. The following snippet is thus legal:
 * <informalexample><programlisting>
 *   gchar *snooped_string;
 *   if (print_hello_world)
 *     {
 *       glocal_string gchar *str = g_strdup ("world!");
 *       g_printf ("Hello %s\n", str);
 *       snooped_string = str;
 *       str = NULL;
 *       // at this point 'str´ is NULL and nothing will happen
 *     }
 *   g_printf ("Woohoo. I just stole the whole %s\n", snooped_string);
 *   g_free (snooped_string);
 * </programlisting></informalexample>
 */
#define glocal_string __attribute__ ((cleanup(_glocal_free_str)))

static void
_glocal_free_str (gchar **strp)
{
  if (strp && *strp)
    g_free (*strp);
}

#define glocal_object __attribute__ ((cleanup(_glocal_unref_object)))

static void
_glocal_unref_object (void *ptraddr)
{
  GObject **objp = (GObject**) ptraddr;
  if (objp && *objp)
    g_object_unref (*objp);
}

G_END_DECLS

#endif /* __GLIB_GCC_H__ */

/* gcc glocaltest.c -g -o glocaltest $(pkg-config --libs --cflags glib-2.0 gobject-2.0 gio-2.0) */

#include <glib.h>
#include <gio/gio.h>
#include "glib-gcc.h"

gint
main ()
{
  g_type_init ();

  if (1)
    {
      glocal_object GFile *file =  g_file_new_for_path ("/tmp");
      glocal_string gchar *basename = g_file_get_basename (file);
      g_debug ("Basename is '%s'", basename);
      // look ma' no leaks!
    }

  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]