Переносимый эквивалент __attribute __ gcc (очистка) - PullRequest
15 голосов
/ 01 декабря 2009

Недавно я наткнулся на расширение 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 ...

Ответы [ 5 ]

8 голосов
/ 01 декабря 2009

Там нет переносимого пути в C.

К счастью, это стандартная функция C ++ с деструкторами.

Edit:

MSVC, по-видимому, имеет ключевые слова __try и __finally, которые также могут использоваться для этой цели. Это отличается от обработки исключений в C ++, и я думаю это доступно в C.

Я думаю, вы обнаружите, что cleanup и try / finally не используются широко, в частности, из-за неявной поддержки в C ++, которая «достаточно близка» к C, чтобы люди, интересующиеся поведением, могли переключить свой код на C ++ с помощью легкость.

4 голосов
/ 11 августа 2010

Первая половина вашего вопроса - это портативный способ сделать это.

0 голосов
/ 13 марта 2019

__attribute__(cleanup) не привязан к gcc, он также поддерживается clang и icc, что делает msvc единственным основным компилятором, который его не поддерживает (и этот в любом случае довольно бесполезен для современной разработки на C).

Таким образом, даже если он не соответствует стандарту ISO, его можно считать переносимым для большинства практических целей.

0 голосов
/ 03 декабря 2009
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);
}
0 голосов
/ 01 декабря 2009

Вы можете использовать boost :: shared_ptr для этой цели.

boost::shared_ptr<char> buffer(p, cleanup);
...