2009-12-01 6 views
13

Recientemente me encontré con una extensión de gcc que he encontrado bastante útil: __attribute__(cleanup)portátil equivalente a __ __attribute de gcc (limpieza)

Básicamente, esto le permite asignar una llamada de limpieza a una variable local en el momento que sale de alcance . Por ejemplo, dada la siguiente sección de código, toda la memoria debe mantenerse y manejarse explícitamente en todos los casos dentro de la llamada al 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); 
} 

Sin embargo, mediante el uso de la extensión que se puede reducir a

#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 */ 
} 

Ahora toda la memoria se recupera sobre la base de alcance sin el uso de anidar si/else o Ir construcciones acoplados con una memoria consolidada liberar la sección de la función. Me doy cuenta de que el uso de goto podría evitarse allí para un constructo if/else más anidado (así que, por favor, no hay guerras santas en el goto ...) y que el ejemplo es artificial, pero el hecho es que esto puede ser una característica bastante útil.

Lamentablemente, hasta donde yo sé, esto es específico de gcc. Me interesan las formas portátiles de hacer lo mismo (si es que existen). ¿Alguien ha tenido experiencias al hacer esto con algo más que gcc?

EDITAR: Parece que la portabilidad no está en juego. Teniendo en cuenta que, ¿hay una manera de hacer esto fuera de del espacio gcc? Parece que a una característica agradable para ser gcc-específica ...

+0

algo relacionado: http://stackoverflow.com/questions/1602398/linux-dlopen-can-a-library-be-notified-when-it-isloaded – jldupont

+0

Eso es un poco grueso para lo que Estoy buscando. En cualquier caso, parece que esa solución todavía es específica de gcc (para la respuesta aceptada) o relacionada con C++ para la respuesta basada en la clase. – ezpz

Respuesta

8

No hay manera portátil en C.

Afortunadamente es una característica estándar de C++ con los destructores.

Editar:

MSVC parece tener __try y __finally palabras clave que se pueden utilizar para este propósito también. Esto es diferente que el manejo de excepciones C++ y yo pensar está disponible en C.

creo que usted encontrará que la limpieza y el try/finally no son ampliamente utilizados específicamente por el apoyo implícito en C++, que es "lo suficientemente cerca" de C para que las personas interesadas en el comportamiento puedan cambiar su código a C++ con facilidad.

+0

Ok, me he actualizado para ignorar las preocupaciones de portabilidad. Fuera de eso, ¿conoce formas de hacerlo fuera de gcc? – ezpz

-5

Puede usar boost :: shared_ptr para tal fin.

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

La pregunta es C-específica. Entiendo las facilidades 'auto_ptr' y' boost :: ', lamentablemente no se aplican a C. – ezpz

-2
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); 
} 
3

La primera mitad de su pregunta es la manera portátil para hacerlo.

Cuestiones relacionadas