How to Create Constructors for Structures in C

cdata structures

The problem

I have this structure that I want to create a "constructor" for it.

struct example {
    int x, y, z; /* various members */
    struct another *another; /* pointer to another structure */
}

The two different ways I know of

  1. Using functions that create and delete structures on heap

I can create structures by making functions that allocates them on the heap like this:

/* create example */
struct example *example_new(int x, int y, int z) {
    struct example *p = malloc(sizeof *p);
    p->x = x;
    p->y = y;
    p->z = z;
    p->another = another_new();
}

/* delete example */
void example_new(struct example *p) {
    another_del(p->another);
    free(p);
}
  1. Using functions that initializes and frees memory for structure through pointer

Or I could initalize the structure by passing pointer to the function and have the user responsible for allocating and deallocating memory for it.

/* initalize example */
void example_init(struct example *p, int x, int y, int z) {
    assert(p);
    p->x = x;
    p->y = y;
    p->z = z;
    p->another = another_new();
}

/* free memory allocated for example */
void example_free(struct example *p) {
    another_del(p->another);
}

My thoughts

I usually prefer first approach when creating recursive structures (like Trees and Linked Lists) but use the second approach in all other cases.

I tried to use the second approach for a recursive structure and it turned out to be quite messy.

The question

How do you choose between these two ways? Is there a third way you would use to solve this problem?

Best Answer

There is no answer that's always going to be the right one, because different programs will have different needs. If you have enough information to make an informed call one way or the other, that's the way you should go. (For example, if your program is required to have the highest throughput possible, forcing a malloc()/free() pair each time some function needs to use your structure probably isn't going to fly.)

If you're going to build a general-purpose library, it isn't much additional effort to build it in a way that supports both:

void example_init(struct example *p, int x, int y, int z) - Initializes the structure pointed at by p. This can be called by anyone who has a struct example whether it's an automatic, allocated on the heap or pulled out of a pool.

void example_destroy(struct example *p) - Does whatever is necessary to de-initialize the structure pointed at by p. (In your case, this would be freeing the memory allocated for the another member.) Note that it does not free p, because it has no knowledge of whether or not the structure is on the heap or if the caller isn't going to re-use it by calling example_init() again.

struct example * example_new(int x, int y, int z) - Allocates space for the structure on the heap, calls example_init() against it and returns the pointer.

void example_del(struct example * p) - Calls example_destroy(p) and then frees p.

There is a hazard to this approach, which is that someone could try to do pairs of example_init()/example_del() or example_new()/example_destroy() calls. Tools like valgrind and some implementations of free() can weed those problems out automagically. Another approach would be to set aside a bit somewhere in the structure that can be set when the structure was on the heap and use assertions to complain if someone goes about it the wrong way. (example_del() would need to clear the bit before calling example_destroy().)

Related Topic