Язык Си не делает ничего, о чем вы явно не говорите.
Нет автоматически вызываемых деструкторов, и это хорошо и плохо (поскольку ошибки в деструкторах могут бытьболь).
Простой способ получить автоматическое поведение деструктора - это использовать область видимости для конструирования и разрушения вещей.Это может стать уродливым, поскольку вложенные области видимости перемещают все дальше и дальше вправо.
if (var = malloc(SIZE)) { // try to keep this line
use_var(var);
free(var); // and this line close and with easy to comprehend code between them
} else {
error_action();
}
return; // try to limit the number of return statements so that you can ensure resources
// are freed for all code paths
Попытка сделать ваш код таким, насколько это возможно, поможет, хотя это не всегда возможно.
Хорошей идеей является создание набора макросов или встроенных функций, которые инициализируют ваши объекты.Также создайте другой набор функций, которые выделяют память ваших объектов и передают ее функциям инициализатора.Это позволяет легко инициализировать как локальные, так и динамически размещенные объекты.Подобные операции для деструктороподобных функций также являются хорошей идеей.
Использование методов ОО является хорошей практикой во многих случаях, и для этого в C просто требуется немного больше ввода (но обеспечивает больший контроль).Путтеры, геттеры и другие вспомогательные функции могут помочь поддерживать объекты в согласованных состояниях и уменьшить изменения, которые необходимо внести при обнаружении ошибки, если вы можете сохранить интерфейс таким же.
Вам также следует обратить внимание наperror
функция и errno
"variabl".
Обычно вы хотите избегать использования каких-либо подобных исключений в C. Я обычно стараюсь избегать их и в C ++, и использую их только для действительно плохихошибки - те, которые не должны происходить.Одна из главных причин их избегания заключается в том, что в C не существует магических вызовов деструкторов, поэтому нелокальные GOTO часто будут пропускать (или иным образом портить) некоторый тип ресурса.При этом в C есть вещи, которые предоставляют аналогичные функциональные возможности.
Основным исключением, как механизм в C, являются функции setjmp
и longjmp
.setjmp
вызывается из одного места в коде и передается (непрозрачная) переменная (jmp_buf), которая позже может быть передана в longjmp
.Когда выполняется вызов longjmp
, он фактически не возвращается к вызывающей стороне, а возвращается как ранее вызванный setjmp
с этим jmp_buf.setjmp
вернет значение, указанное при вызове longjmp
.Обычные вызовы setjmp
возвращают 0.
Другое исключение, например, функциональность, зависит от платформы, но включает сигналы (которые имеют свои собственные ошибки).
Другие вещи, на которые следует обратить внимание:
Макрос assert
, который можно использовать для завершения программы при сбое параметра (некоторого логического теста).Звонки на номер assert
исчезают, когда вы #define NDEBUG
перед вами #include <assert.h>
, поэтому после тестирования вы можете легко удалить утверждения.Это действительно хорошо для тестирования указателей NULL перед их разыменованием, а также некоторых других условий.Если условие не выполнено, assert
пытается напечатать имя исходного файла и номер строки неудачного теста.
Функция abort
вызывает сбой программы, не выполняя всю очистку этого вызова exit
делает.Это может быть сделано с помощью сигнала на некоторых платформах.assert
звонки abort
.