Patterns: Creation and Destruction Stack

Virtually 100% of all memory leaks are preventable, assuming the programmer knows where to look. In many cases, the leaks occur because a programmer has failed to destroy what he has created, but it can become more complicated than that.

Creation Stack: The Order Matters

In many cases, we allocate memory as we use it, and we keep it at a simple layer. I’ve nearly lost track of how many calls to calloc() or malloc() I’ve hard-coded in the past few months alone.

This simple allocation is great, because it lets us dynamically generate variables and store them. These variables can be simple (like char or int), or they can be structures of varied complexity.

The most complex structures we allocate require us to allocate within the struct. Consider the following structure:

struct potato

{

struct potato *next;

char * string;

int size;

}

This structure contains not one, but two pointers, and we need these pointers to point to something. Generally speaking, we would want to create a simple constructor that does something like this:

struct potato * make_potato()

{

struct potato * hi = calloc(sizeof(potato));

return hi;

}

This would initialize a potato with null pointers and a size of 0. However, it’s usually more useful for us to fill in some values on construction of a structure like this:

struct potato * make_potato(int input_size, const char * something)

{

struct potato * hi = calloc(sizeof(potato));

hi->size = input_size;

hi->string = calloc(size * sizeof(char));

strncpy( hi->string, something, size);

return hi;

}

In this case, we not only allocate a structure, but we allocate within the structure. This can get messy very quickly.

Destruction: Follow it up the stack

The rule to prevent memory leaks here is fairly simple: every destructor should be the inverse of its constructor.

If the constructor is simple, the destructor is equally simple:

int eat_potato(struct potato * hi)

{

free(hi);

return 0;

}

However, when the constructor gets more complex, we have to treat it like a stack. That means that we should run every destructor in the inverse order of construction, so that we make sure to get everything freed before all pointers to it are lost.

int eat_potato(struct potato * hi)

{

free(hi->string);

free(hi);

return hi;

}

Lesson: You build a building from the ground up, and you tear it down from the top. The same goes for structures.

Facebook Auto Publish Powered By : XYZScripts.com