у него идея -- обнулить указатель, чтобы при повторном free был ноль и грох. Такая дисциплина часто встречается в промышленном коде -- это лучше чем ничего.
Я недавно писал игрушечную прогаммку на C, и использовал подход, применяемый мною в Java — test first. То есть я писал параллельно 2 файла — файл с юниттестами, в котором тестировал текущий модуль и сам файл с кодом, причём сначала писал тесты, а потом код, реализующий тесты.
Все тесты прогонялись в make-е под valgrind-ом и валились, если valgrind находил какие то ошибки или утечки.
В итоге не тестировались только ситуации, когда malloc возвращает 0 (при желании можно и их было бы тестировать, но было лень) и ощущение уверенности в надёжности кода было куда выше, чем если бы я писал просто так.
Собственно интересно — кто-нибудь такой подход в промышленном C применяет? Или грамотным C-программистам это не надо?
>Все тесты прогонялись в make-е под valgrind-ом и валились, если valgrind находил какие то ошибки или утечки.
Кстати, был бы любопытно взглянуть на реализацию тестов с использованием valgrind'а. Должно быть не сложно, но всё-таки хотелось бы взглянуть как это реализуют другие разработчики. Покажешь? :)
> Кстати, был бы любопытно взглянуть на реализацию тестов с использованием valgrind'а. Должно быть не сложно, но всё-таки хотелось бы взглянуть как это реализуют другие разработчики. Покажешь? :)
было бы куда как интереснее посмотреть на тест план для тестирования некого сервиса, который должен работать 24x7 и в котором где-то в рантайме в зависимости от каких-то нелинейных условий течёт память. по чуть-чуть но со временем накапливается. возьмём в качестве примера ну скажем apache.
Если мы можем моделировать обстановку, в которой он течёт, пускаем под valgrind-ом, ждём сутки, стопаем и смотрим, что утекло. Если не можем, тогда видимо компилируем с отладочными malloc-ами, отдаём клиенту и анализируем логи, когда начинает течь.
free() освобождает область памяти, на которую указывает ptr, которая быть выделена ранее посредством malloc(),
calloc() или realloc(). Иначе, если free(ptr) был уже вызван ранее, результат операции не определен. Если ptr
равен NULL, то ничего не происходит.
> Какую-то муть вы сказали. Обнуление указателя это способ избежать гниения кода, а не быдлокодерство.
не очевидный на самом деле вопрос. да, обнуляя указатели можно в определённой мере застраховаться от того, что если будет больше одного free/delete, то программа по крайней мере не упадёт в корку. с другой стороны, само по себе наличие явного множественного освобождения одного и того же ресурса может быть [и скорее всего является] ошибкой. в этом случае зануление скроет тактическую ошибку но может дать ход стратегической, т.е. вместо того, чтобы просто упать программа будет продолжать что-то делать и уже не факт, что то, что нужно. в общем, есть за есть против.
>в этом случае зануление скроет тактическую ошибку но может дать ход стратегической, т.е. вместо того, чтобы просто упать программа будет продолжать что-то делать и уже не факт, что то, что нужно.
ЕМНИП попытка записи по нулевуму указатели лили чтения вызовет "гарантированную" ошибку доступа по нулевому адресу, если не обнулить то попытка записать что-либо может и не вызвать ошибки - таки аргументы приводятся обычно в книгах.
> в этом случае зануление скроет тактическую ошибку но может дать ход стратегической
в приведенном no-dashi примере при повторном free нулевого указателя срабатывает ассерт -- т.е. этот код как раз манифестирует ошибку, в то время как просто двойной фри мог и не вызвать моментальное падение.
> ЕМНИП попытка записи по нулевуму указатели лили чтения вызовет "гарантированную" ошибку доступа по нулевому адресу, если не обнулить то попытка записать что-либо может и не вызвать ошибки - таки аргументы приводятся обычно в книгах.
> Если вы сознательно позвляете себе множественные free/delete,
> то вам нужен какой-либо вариант GC. Если вы этого не понимаете, то RTFM.
class foo {
public :
foo() : p_(0) {}
~foo() {
delete []p_;
}
private :
int *p_;
};
// wbr
добавлю лишь уточнение... например в glib есть функция g_free, так она при попытке освободить уже освободившееся вываливает просесс на double free corruption. так что я стараюсь явно обозначить переменную как NULL после освобождения памяти, ибо если я в каком-то месте сделал free(a), а где-то дальше по коду пытаюсь сделать if (a)... то сие не будет иметь действительную истину.
>Программа не освобождающая его вообще суть идеал?
С вашей точки зрения, идеал - программа, которая по несколько раз
освобождает память и по несколько раз открывает и закрывает одни и те же файлы.
На всякий случай, для верности.
Вот это и называется быдлокодерство.
Опять мимо, заметьте, что своего мнения я не высказывал, а подбирать методом научного тыка вы его будете долго, что я вам хотел сказать, я уже сказал, вы не услышали.
>>Я писал не про обнуление указателя. Программа, по четыре раза освобождающая один и тот же указатель - криворукость и быдлокодерство.
>Программа не освобождающая его вообще суть идеал?
Я внятно озвучил свою позицию, а вы зачем-то совершенно необосновано
стали на меня нападать, сводя мои слова к абсурду.
Я использовал ваш способ, который вам не понравился.
>Не так, кроме того у вас плохой стиль, даже одну строчку цикла лучше оборачивать {}.
Вы написали бред. Один из самых правильных стилей программирования -
стиль разработчиков ядра. В коде ядра используются оба способа - без
скобок и со скобками, причем оговаривается, что стиль основывается в
первую очередь на K&R, где скобки как раз не ставятся.
"даже одну строчку цикла лучше оборачивать {}" - это значит? :
___________________________
for (i = 0; i < 10; i ++) {
link[i] = NULL;
}
===========================
Вот это уже маразм.