Home ¦ Posts ¦ Books ¦ Articles ¦ Talks ¦ Notes

Resource Acquisition Is Initialization (RAII) in C

GCC's C compiler allows you to define various variable attributes. One of them is the cleanup attribute (which you can also write as __cleanup__) which allows you to define a function to be called when the variable goes out of scope (for example, before returning from a function). This is useful, for example to never forget to close a file or freeing the memory you may have allocated. Next up is a demo example defining this attribute on an integer variable (which obviously has no practical value). I am using gcc (GCC) 4.7.2 20121109 on Fedora 22.

Demo

The next code listing declares an integer variable, avar with the cleanup attribute set such that the function clean_up is called before main() returns:

# include <stdio.h>
void clean_up(int *final_value)
{
    printf("Cleaning up\n");
    printf("Final value: %d\n",*final_value);
}

 int main(int argc, char **argv)
 {
     /* declare cleanup attribute along with initiliazation
     Without the cleanup attribute, this is equivalent
     to:int avar = 1;
     */
     int avar __attribute__ ((__cleanup__(clean_up))) = 1;
     avar = 5;
     return 0;
 }

The clean_up function above accepts an argument which is an integer pointer. This is a pointer to the integer variable avar for which this function is called due to the __cleanup__ attribute being set. When you compile and execute the program, you should see the following output:

$ gcc -Wall cleanup_attribute_demo.c
$ ./a.out
Cleaning up
Final value: 5

Next, I will present a hopefully more useful example.

Cleaning up temporary files

In your programs, you may need to create one or more temporary files for some reason. Most likely, you would want to remove them after your program exits. Defining a __cleanup__ attribute on the FILE * variable (assuming stream I/O) and setting it to an appopriate cleanup function sounds like something which could be put to good use. We don't have to manually call the cleanup function.

Here is the program:

/* Defines two cleanup functions to close and delete a temporary file
 and free a buffer
 */

 # include <stdlib.h>
 # include <stdio.h>

 # define TMP_FILE "/tmp/tmp.file"

 void free_buffer(char **buffer)
 {
   printf("Freeing buffer\n");
   free(*buffer);
 }

 void cleanup_file(FILE **fp)
 {
   printf("Closing file\n");
   fclose(*fp);

   printf("Deleting the file\n");
   remove(TMP_FILE);
 }

 int main(int argc, char **argv)
 {
   char *buffer __attribute__ ((__cleanup__(free_buffer))) = malloc(20);
   FILE *fp __attribute__ ((__cleanup__(cleanup_file)));

   fp = fopen(TMP_FILE, "w+");
   if (fp != NULL)
     fprintf(fp, "%s", "Alinewithnospaces");

  fflush(fp);
  fseek(fp, 0L, SEEK_SET);
  fscanf(fp, "%s", buffer);
  printf("%s\n", buffer);
  return 0;
  }

The above program creates a temporary file in the location specified by TMP_FILE, writes a line of text with no spaces, resets the file pointer to the beginning and reads it back. In line no.32, I declare a variable fp of type FILE* and define the __cleanup__ attribute such that the function cleanup__file will be called upon the return of the main() function. This function closes the file and also deletes it from the file system. When you run your program, you should see the following output:

Alinewithnospaces
Closing file
Deleting the file
Freeing buffer

If you check the existence of the file specified by TMP_FILE, you will see that it doesn't exist. Note how I also use define the __cleanup__ attribute on the variable, buffer to automatically free memory as well.

Share on: Diaspora*TwitterFacebookGoogle+Email

© Amit Saha. Built using Pelican. Customised theme based on the one by Giulio Fidente on github.