#c
Допустим есть кусок кода: char *ptr = (char*)malloc(needed_size); if (!ptr) { error_handling(); } else { do_something_without_freeing_ptr(); free(ptr); ptr = 0; } Может ли вызов free не отработать/отработать неправильно и к каким последствиям это может привести? Подразумевается, что между вызовом malloc и free выделенная память не освобождается, значение указателя не изменяется. Не лучше ли, во избежание случайного изменения значения ptr, писать: char * const ptr = malloc(needed_size); Это не избавит от возможности написать free(ptr); free(ptr);, но по крайней мере убережет от чего-то типа ptr = NULL;
Ответы
Ответ 1
free определена как функция, не возвращающая значений, т.е. возможности вернуть ошибку у неё нет. Если ей передать указатель полученный не от calloc, malloc, realloc, либо вызвать повторно для одного и того же указателя или изменить байты за пределами запрошенного массива, действия зависят от реализации. Обычно это приводит к непредсказуемым ошибкам в программе, возможно в совершенно другом месте. Такие ошибки трудно локализовать. К примеру, в начале выделенного куска памяти перед тем, на что указывает указатель, обычно находится заголовок — структура с информацией об этом куске и о следующем. Кроме этого, где-то может быть информация о свободных кусках. Если, например, в результате функции gets() будет испорчен заголовок для следующего блока, то проявиться эта ошибка может даже не когда этот блок будет выделен malloc, а когда этот блок будет освобождаться. Есть библиотеки реализующие набор функций calloc, malloc, realloc, free с дополнительными средствами обнаружения их ошибочного использования. Написать char * const ptr = malloc(needed_size); можно, но это не гарантирует, что вы не скопируете указатель в другую переменную или примените индекс за пределами [0; needed_size[.Ответ 2
Согласно Стандарту C11 (7.22.3.3/2): The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined. Т.о. если память была корректно выделена и не была после этого ещё освобождена с помощью free или realloc, всё должно быть хорошо. Если провести некоторую параллель с c++, то необходимость отсутствия ошибок в функции free чем-то сродни необходимости не бросать исключения в деструкторах. На счет дополнительного const к указателю - идея хорошая и правильная. Позволяет выявлять ситуации непреднамеренной модификации или повторного использования переменной в разных контекстах. Главное здесь, не переборщить и не завалить код constами там, где от этого совсем нет профита. С другой стороны, невозможность изменить значение указателя на NULL будет препятствовать защите от повторного освобождения. Т.к. если указатель мутабельный, можно писать так и не бояться последствий: T* ptr = malloc(/*...*/); // ... free(ptr); ptr = NULL; free(ptr); // Безопасно Понятно, что для T* const ptr такое будет невозможно.Ответ 3
Насколько мне известно, стандартный С не позволяет контролировать неконсистентный heap и вообще какие-либо ошибки при освобождении памяти. Поэтому нужно пользоваться или возможностями используемой операционной системы, как GetProcessHeap, HeapAlloc, HeapFree, HeapValidate под Windows или расширениями используемого компилятора, см. здесь и здесь.
Комментариев нет:
Отправить комментарий