Некоторое время назад, один товарищ мне посоветовал попробовать g_autoptr (). Тогда у меня не было на это времени, а вчера добрался потыкать.
// gcc `pkg-config --libs --cflags glib-2.0` -g g_autoptr.c
#include <glib.h>
G_DEFINE_AUTOPTR_CLEANUP_FUNC (gchar, g_free);
void
print_elem (gpointer data,
gpointer user_data)
{
g_print ("GList: %s\n", (gchar *) data);
}
gint
main (gint argc,
gchar *argv[])
{
g_autoptr(gchar) tmp = g_strdup ("Hello, I'm gchar!");
g_autoptr(GList) lst = NULL;
lst = g_list_append (lst, tmp);
g_print ("gchar: %s\n", tmp);
g_list_foreach (lst, (GFunc) print_elem, NULL);
return 0;
}
Запускаем под valgrind
$ valgrind --tool=memcheck --leak-check=full ./g_autoptr
==9620== HEAP SUMMARY:
==9620== in use at exit: 2,094 bytes in 6 blocks
==9620== total heap usage: 22 allocs, 16 frees, 68,943 bytes allocated
==9620==
==9620== LEAK SUMMARY:
==9620== definitely lost: 0 bytes in 0 blocks
==9620== indirectly lost: 0 bytes in 0 blocks
==9620== possibly lost: 0 bytes in 0 blocks
==9620== still reachable: 2,094 bytes in 6 blocks
==9620== suppressed: 0 bytes in 0 blocks
gchar *
вместо g_autoptr(gchar)
, то будет так
$ valgrind --tool=memcheck --leak-check=full ./no_g_autoptr
==9705== HEAP SUMMARY:
==9705== in use at exit: 2,136 bytes in 8 blocks
==9705== total heap usage: 22 allocs, 14 frees, 68,943 bytes allocated
==9705==
==9705== 42 (24 direct, 18 indirect) bytes in 1 blocks are definitely lost in loss record 7 of 8
==9705== at 0x4C2AC10: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==9705== by 0x4E82769: g_malloc (in /usr/lib64/libglib-2.0.so.0.4501.0)
==9705== by 0x4E99DC2: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.4501.0)
==9705== by 0x4E78EE3: g_list_append (in /usr/lib64/libglib-2.0.so.0.4501.0)
==9705== by 0x400848: main (no_g_autoptr.c:16)
==9705==
==9705== LEAK SUMMARY:
==9705== definitely lost: 24 bytes in 1 blocks
==9705== indirectly lost: 18 bytes in 1 blocks
==9705== possibly lost: 0 bytes in 0 blocks
==9705== still reachable: 2,094 bytes in 6 blocks
==9705== suppressed: 0 bytes in 0 blocks
Ну и пример исходного кода от разработчика этой штуки
{
g_autoptr(GObject) object;
g_autoptr(gchar) tmp;
g_auto(GQueue) queue;
g_queue_init (&queue);
object = g_object_new (...);
tmp = g_strdup_printf (...);
// no free required
}
Кстати, разработчики сейчас часто используют конструкцию
#define GS_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \
static inline void name (void *v) \
{ \
if (*(Type*)v) \
func (*(Type*)v); \
}
#define _cleanup_error_free_ __attribute__ ((cleanup(gs_local_free_error)))
GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free)
_cleanup_error_free_ GError *error = NULL;