LINUX.ORG.RU

Два философских вопроса по malloc/free

 , , ,


0

2

Здравствуйте. За месяц читания чужого Си-кода (и писания своего), меня не покидают два концептуальных вопроса про кучу

  1. Много где вижу конструкцию
    if(pth != NULL) free(pth);
    
    Несмотря на то, что в мане написано If ptr is NULL, no operation is performed. Откуда такое недоверие к манам?
  2. Каждый раз когда делаю malloc/free для локальных переменных (особенно если в цикле), в одном месте появляется неприятный зуд на тему «Память же фрагментируется. Нельзя часто выделять освобождать. Особенно много маленьких кусочков.» Оправдан ли этот зуд или все там норм с кучей?
★★★★★

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

Часто такой код пишут в контексте:

if(p != NULL)
{
  free(p);
  p = NULL;
}
Чтобы повторно не вызвать free на одном и том же указателе, что приведет к крэшу.

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

Кстати, да. Такое тоже видел

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

А еще лучше — вообще сделать макросы:

#define ALLOC(type, var, size)  type * var = ((type *)my_alloc(size, sizeof(type)))
#define MALLOC(type, size) ((type *)my_alloc(size, sizeof(type)))
#define FREE(ptr)  do{if(ptr){free(ptr); ptr = NULL;}}while(0)

void *my_alloc(size_t N, size_t S){
	void *p = calloc(N, S);
	if(!p) ERR("malloc");
	//assert(p);
	return p;
}
И тогда можно не париться насчет double free или проверки возвращаемого malloc'ом.

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

И тогда можно не париться насчет double free

Сюрприз - на одну область памяти может указывать несколько указателей.

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

Это уж проблема того, кто эту толпу указателей развел!

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

Когда уже си осилишь и перестанешь писать на С/С++?

Макрос фрии вообще не имеет смысла. Если у тебя где-то есть даблфри - твой код дерьмо и сокрывать это неработающими кастылями глупо.

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

Что за пургу ты насчет C/C++ несешь? Пишу на сях. Нормальных сях.

Макрос фрии вообще не имеет смысла.

Очень даже имеет, потому как, скажем, если сделать просто free(list), когда освободили последний член, то последующее добавление члена в список будет UB!

Царь, ты уже всех достал своим тупым бредом!

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

как обычно даблфри можно избежать дополнительным уровнем косвенности

со своей таблицей соответствия твой_управляемый_хэндл<->железко_адресс и сопуствиующее этой табличке различные хинты для более_лучшего обмазывания памятью

-и вуаля можно ужо и мусор собирать али ещё чё.

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

Очень даже имеет, потому как, скажем, если сделать просто free(list), когда освободили последний член, то последующее добавление члена в список будет UB!

Редко случается ситуация, когда на какое-то место в памяти указывает только один указатель.

char *a = MALLOC(char, 10), *b = a;
FREE(a);
FREE(b); //oops

А вообще, мне не понятно, зачем ТС динамическая память, если он её убивает в конце функции. Пусть использует стек или ареновый/пуловый аллокатор. Основная цель malloc (если не думать, что размер стека ограничен) — это продление времени жизни созданного объекта.

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

Что за пургу ты насчет C/C++ несешь? Пишу на сях. Нормальных сях.

Действительно, прям как в той тут Несколько вопросов новичка по Си (комментарий)

Хорошо, зачем ты кастишь руками воид, который кастить руками надо только в С/С++?

Очень даже имеет, потому как, скажем, если сделать просто free(list), когда освободили последний член, то последующее добавление члена в список будет UB!

Чё? Куда чё добавлять? Ты код-то писать нормально не можешь, чтобы не добавлять куда не надо?

По поводу твоего фри.

int * ptr = malloc(100500); int * ptr2 = ptr + 100; free(ptr); ptr2 - hello, alesha.

Такая же жопа с перебачей в функции, да и везде.

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

Еще лучше писать на плюсах.

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

зачем ТС динамическая память, если он её убивает в конце функции

Для строк же. Сплит, джойн, конкат, форматированный вывод в строку. Тут даже C99 VLA arrays не сильно упростят жизнь.

Сначала заюзал bstrlib. Там если что можно было обернуть память на стеке в bstring, так что malloc сильно не парил. Но всязи с упоротостью этих строк перешел на sds. Значительно проще, но абсолютно всё на аллокациях. И тут начало зудеть )

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

Для строк же. сплит, джойн, конкат, форматированный вывод в строку

поменяй собственный взгляд на «что есть строка» и всё пройдёт..

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

С чего начать?

с исходной задачи должно быть :-)

откуда взялись обилие split/join/concat с (начальными) строками ? синтаксический анализ и трансляция кода/текста ?

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

mock-заглушка для одного девайса с telnet-like протоколом.

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

Можно написать простенький сплиттер, возвращающий указатели на нужные куски исходной строки. А можно тупо вызвать split и получить массив строк

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

Можно написать простенький сплиттер, возвращающий указатели на нужные куски исходной строки

this..возможно даже заюзать bison+flex (не всегда но как правило ДА), чтобы было понятно не только тебе - не все горят желанием разбирать/сопровождать/отлаживать парсеры

а вообще :

«mock-заглушка для одного девайса с telnet-like протоколом» - как оно стало bottle-neck ? что вы озаботились памятью/скоростью ??

покажите код - и вам помогут..

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

Выдели один раз длинный(N*PAGE_SIZE) буфер и в нём играйся, возвращать память в ОС по каждому чиху не обязательно.

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

и в нём играйся

Буфер-то я выделю. Но игрушек для него не завезли (или я не нашел). А игра опасными бритвами (mem*, str*, указатели) высасывает все силы)

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

bison+flex

Да там разделенные пробелами строки. Сплит строки на бизоне - это, ИМХО, достойно размещения на ibash.org.ru )

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

вообще-то бизон нужен не для сплита а чтобы из потока лексем удобно-однотипно получить выражение с которым можно что-то сделать. Вы-ж не для спортивного интереса разбираете «строки разделённые пробелами» ? :-)

PS/ и что-то мне подсказывает что тема топика порождена обилием личного времени ТС чем реальной проблемой ..

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

Сплит

Я както давно сделал себе либу с легковесными строками (правда на C++). Но суть в том что там строка у меня это просто структура:

struct {
  const char *data;
  unsigned length;
}
Причем data ссылается на внешний буффер которым сама строка не владеет. Очень удобно использовать в различных текстовых процессорах (например прочитали строчку с сокета/файла в буффер и нужно ее распарсить). Очень частво весь процесс разбора (сплит, trim, lcut, rcut, substr, и тд) идет без единого malloc/free и без единого memcpy/strcpy/strdup ...

Но конечно там где уже нужно формировать новые строки (join, cat, sprintf) от аллокаций избавится сложнее.

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

Причем data ссылается на внешний буфер которым сама строка не владеет.

Называл бы это не «строка», а «string view».

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

C названиями у меня всегда туго было, бывает сидиш пол часа и думаеш как класс/неймспейс/библиотеку назвать. Уже есть четкое представление по реализации - а названия нет :)

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

С названиями у меня всегда туго было

У всех так. Хорошее название трудно найти.

Просто в данном случае для подобной сущности уже есть готовое имя.

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

Очень удобно

Удобно, но не очень. Нет \0 в конце строки. Это сразу ставит крест почти на всех функциях, принимающих char*. Почти все реализации динамических строки после каждой операции добавляют 0. А sds так вообще возвращает сишную строку, длина которой хранится за несколько байт до начала строки. Удобно - не надо подключать shs.h в основной header-файл

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