Портативный эквивалент gcc __attribute __ (очистка)
Недавно я наткнулся на расширение gcc, которое я нашел довольно полезным: __attribute__(cleanup)
В принципе, это позволяет назначить вызов очистки локальной переменной в момент выхода из области. Например, в следующем разделе кода вся память должна поддерживаться и обрабатываться явно в любом случае во время вызова foo
.
void foo() {
char * buff = ...; /* some memory allocation */
char * buff2 = 0, * buff3 = 0;
if (! buff) {
return;
} else {
buff2 = ...; /* memory allocation */
if (! buff2) {
goto clean_exit;
} else {
/* ... and so on ... */
}
}
clean_exit:
free (buff);
free (buff2);
free (buff3);
}
Однако, используя расширение, которое можно уменьшить до
#define clean_pchar_scope __attribute__((cleanup(pchar_free)))
void pchar_free (char ** c) { free (*c); }
void foo () {
char * buff clean_pchar_scope = ...; /* some memory allocation */
char * buff2 clean_pchar_scope = 0, * buff3 clean_pchar_scope = 0;
if (! buff)
return;
buff2 = ...; /* memory allocation */
if (! buff2)
return;
/* and so on */
}
Теперь вся память восстанавливается на основе области без использования вложенных конструкций if/else или goto в сочетании с секцией освобождения консолидированной памяти функции. Я понимаю, что использование goto можно было бы избежать там для более вложенной конструкции if/else (так что, пожалуйста, никаких священных войн на goto...), и что этот пример надуман, но факт остается фактом: это может быть довольно полезная функция.
К сожалению, насколько я знаю, это спецификация gcc. Меня интересуют любые переносные способы сделать то же самое (если они даже существуют).
Кто-нибудь имел опыт в этом с чем-то отличным от gcc?
EDIT:
Кажется, что переносимость не в игре. Учитывая, что есть ли способ сделать это за пределами gcc-пространства? Кажется приятной особенностью быть gcc-специфической...
Ответы
Ответ 1
В C нет переносного способа.
К счастью, это стандартная функция С++ с деструкторами.
Edit:
У MSVC есть слова __try и __finally, которые могут быть использованы для этой цели. Это отличается от обработки исключений С++, и я думаю, что он доступен в C.
Я думаю, вы обнаружите, что очистка и попытка /, наконец, широко не используются специально из-за неявной поддержки на С++, которая достаточно близка к C, что люди, заинтересованные в поведении, могут переключать свой код на С++ с помощью легкость.
Ответ 2
Первая половина вашего вопроса - это переносимый способ сделать это.
Ответ 3
void foo()
{
char *buf1 = 0, *buf2 = 0, *buf3 = 0;
/** more resource handle */
do {
if ( buf1 = ... , !buf1 ) break;
if ( buf2 = ... , !buf2 ) break;
if ( buf3 = ... , !buf3 ) break;
/** to acquire more resource */
/** to do with resource */
} while (0);
/** to release more resource */
if (buf3) free(buf3);
if (buf2) free(buf2);
if (buf1) free(buf1);
}
Ответ 4
Вы можете использовать boost:: shared_ptr для этой цели.
boost::shared_ptr<char> buffer(p, cleanup);