LINUX.ORG.RU

Автоосвобождение памяти используя g_autoptr ()

 , ,


0

2

Некоторое время назад, один товарищ мне посоветовал попробовать 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;

не джентльменам мы не отвечаем

anonymous ()

gcc'шный костыль для тех, кто до сих пор боится C++. Зачем так жить?

Gvidon ★★★★ ()

А в чём собсно вопрос?

mittorn ★★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

не нужно, а valgrind часто ложные результаты выдаёт

и да, как там та девушка на квартире у знакомого поживает? :)

Harald ★★★★★ ()

Хорошую вещь на букву g не назовут. В глазах рябит от такого стиля

Зачем вообще эти auto? Неужели так сложно сделать руками? Выделил-освободил. Открыл файл-закрыл файл.

У тех кто эту auto-ерунду проталкивает в низкоуровневые языки, наверное все двери с доводчиками и автоматический смыв в унитазе

anonymous ()
Ответ на: комментарий от anonymous

glibc <-- ну нехорошая вещь, так нехорошая

но зачем делать руками, если можно сделать автоматически. К тому же, когда пишешь много кода - можно забыть очистить.

i_gnatenko_brain ★★★★ ()
Ответ на: комментарий от Harald

а можно пример где описывается как и почему он выдаёт ложные результаты?

тебе шкворца то не жалко ?) а вообще, нормально.

i_gnatenko_brain ★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

в документации валгринда, например, там перечислены разные ситуации с ложными срабатываниями

Harald ★★★★★ ()

Ну и вопрос: что будет, если такая переменная не проинициализирована или её инициализация завершилась с ошибкой? В плюсах этот вопрос решается наличием конструкторов по умолчанию и тем, что деструктор не будет вызван, если конструктор кинул исключение, а здесь что?

Gvidon ★★★★ ()
Последнее исправление: Gvidon (всего исправлений: 1)
Ответ на: комментарий от i_gnatenko_brain

но зачем делать руками, если можно сделать автоматически

Зачем тогда писать на С, даже в С++ с этим поудобнее.

можно забыть очистить

Если течет незаметно, нечего и напрягаться. Все равно идеально не сделаешь, хоть с этим g*, хоть без него. Но без него хоть можно сохранить читаемость, а это важнее чем 24 потеряных байта.

anonymous ()
Ответ на: комментарий от anonymous

Если течет незаметно, нечего и напрягаться

Убиват!

Gvidon ★★★★ ()
Ответ на: комментарий от Gvidon

Убиват!

Иди на разработчиках говноплагинов к браузерам потренируйся. Там не то что течет, ведрами хлещет

anonymous ()

А не проще вообще на Vala тогда писать?

i-rinat ★★★★★ ()
Ответ на: комментарий от anonymous

а это важнее чем 24 потеряных байта.

Убиват(2)!

mittorn ★★★★★ ()

Ересь какая то. Люди в конец обленились. Уже память освобождать им лень.
Даже подсчет ссылок на объект мне видится лучшей идеей, чем это.

Cactus64k ()
Ответ на: комментарий от i-rinat

не уверен, что stable vala его использует. по крайне мере она сейчас не использует G_DECLARE_*_TYPE макросы когда преобразовывает код в C.

i_gnatenko_brain ★★★★ ()

Ну я уже говорил что я думаю по этому поводу: если ты хочешь контролировать память вручную, то не надо пользоваться auto, а если ты хочешь чтобы память за тебя контролировал компилятор, то не надо пользоваться C.

glib занимается тем, что, по сути, превращает C в C++ но только хуже. gobject гораздо хуже классов из C++, glib-контейнеры гораздо хуже stl, и вот пожалуйста, свежий пример — g_autoptr. Зачем преращать C в убогую версию C++, когда C++ и так уже есть?

morse ★★★★★ ()
Ответ на: комментарий от anonymous

А потом глянут сторонние люди в твой код, увидят что там натекло несколько сотен мегабайт и подумают, что ты только что с пхп слез.

Cactus64k ()
Ответ на: комментарий от mittorn

24 потеряных байта.

Убиват(2)!

За 24 байта? Если у тебя будет в секунду столько убегать, то за год непрерывной работы получится 750М. Для кучи современного софта это было бы отличным достижением

anonymous ()
Ответ на: комментарий от i_gnatenko_brain

Нет, причём тут это. Там компилятор сам следит за временем жизни переменных. Та же задача решается, только во время компиляции, а не во время исполнения.

i-rinat ★★★★★ ()
Ответ на: комментарий от anonymous

сишка уже низкоуровневой стала? отсыпь, а?

FIL ★★★★ ()
Ответ на: комментарий от i-rinat

Здесь тоже всё во время компиляции разруливается, gcc просто подставляет вызов функции перед выходом переменной из области видимости.

Gvidon ★★★★ ()
Ответ на: комментарий от i-rinat

мне почему-то казалось, что vala перегоняет код в C, а дальше компиляй через gcc

i_gnatenko_brain ★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

vala перегоняет код в C, а дальше компиляй через gcc

Сейчас по умолчанию valac просто собирает исполняемый файл.

i-rinat ★★★★★ ()
Ответ на: комментарий от FIL

сишка уже низкоуровневой стала?

а что тогда по-твоему низкоуровневое? кроме ассемблера, конечно

reprimand ★★★★★ ()
Ответ на: комментарий от morse

Да, я помню твои мысли)

А чем glib контейнеры хуже stl? Я stl не знаю, поэтому это не троллинг.

i_gnatenko_brain ★★★★ ()
Ответ на: комментарий от reprimand

машинные коды, набиваемые вручную в двоичной системе переключателями )

Harald ★★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

А чем glib контейнеры хуже stl?

Отсутствием типобезопасности (это общая проблема обобщённого программирования на Це), уродским синтаксисом и отсутствием стандартных алгоритмов, например.

Gvidon ★★★★ ()
Ответ на: комментарий от Gvidon

Типобезопасность в глиб контейнерах есть, на сколько я знаю.

Про синтаксис - на вкус и цвет.

Каких алгоритмов, например?

i_gnatenko_brain ★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

Типобезопасность в глиб контейнерах есть, на сколько я знаю.

На этапе исполнения. На этапе компиляции — нет. По этой же причине в них невозможен статический анализ кода. С этим в glib вообще печально: все приходится держать в уме, из-за чего написание больших модулей превращается в пытку.

morse ★★★★★ ()
Ответ на: комментарий от i_gnatenko_brain

Про синтаксис - на вкус и цвет.

g_array_index(my_array, MyCoolClass, i)

против

my_array[i]
О чём тут спорить вообще? Причём, второй вариант ещё и намного безопасней, так как не использует никаких приведений типов.

Каких алгоритмов, например?

Любых. Хоть for_each или copy.

Gvidon ★★★★ ()
Последнее исправление: Gvidon (всего исправлений: 2)
Ответ на: комментарий от Harald

машинные коды, набиваемые вручную в двоичной системе переключателями )

я, видимо, буду капитаном, вставляя ответ заметку
Но, к сожалению, люди не меняются.

Harald ★★★ (06.05.2015 13:49:31) в биореактор бы тебя за такие идеи :) ; наглец, типичный великовозрастный альфа-школьник

уж прости =)

reprimand ★★★★★ ()

Ничего не понимаю! И это программисты? Говно какое-то, пид[..]ы, б[..]дь. Родина им дала C++ — пиши с RAII! Используй умные указатели, б[..]дь! «Не хочу, хочу жрать говно!» Что такое? Это поддерживаемый код? Суки, мудачьё — чистые сишники. Костылей насочиняли, говно жрут — пи[..]ы, б[..]дь, ёб[..]е.

anonymous ()
Ответ на: комментарий от FIL

сишка уже низкоуровневой стала? отсыпь, а?

И ты.

Stil ★★★★★ ()
Ответ на: комментарий от anonymous

а это важнее чем 24 потеряных байтов

Убиват(3)!

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.