I've been working on a library that includes a list-like structure, which I use internally multiple times to store different types of structs. However, I'm not entirely confident with my ability to safely manage memory in C yet, so I'd appreciate if someone could let me know if there's anything wrong with my code (it seems to work just fine.)
This is the code for the list structure (with some bits from the associated header put at the top for simplicity.)
// Put this at the top of structs to make it possible to use them in a cg_mem_list #define CG_ITEMIZABLE int cg_index; // Free extra spaces after this many exist #define CG_MEM_EXTRAS 10 typedef struct cg_mem_item { CG_ITEMIZABLE } cg_mem_item; typedef struct cg_mem_list { cg_mem_item** items; int num, capacity, itemsize; } cg_mem_list; void cg_new_mem_list (cg_mem_list* list, int itemsize) { list->items = 0; list->num = 0; list->capacity = 0; list->itemsize = itemsize; } cg_mem_item* cg_mem_list_add (cg_mem_list* list) { cg_mem_item* mitem = malloc (list->itemsize); if (list->capacity - list->num < 1) { list->capacity++; list->items = realloc (list->items, list->capacity * sizeof (cg_mem_item*)); } mitem->cg_index = list->num; list->items[list->num++] = mitem; return mitem; } void cg_mem_list_remove (cg_mem_list *list, cg_mem_item *item) { list->num--; int index = item->cg_index; if (index < list->num) { list->items[index] = list->items[list->num]; list->items[index]->cg_index = index; } if (list->capacity - list->num > CG_MEM_EXTRAS) { list->capacity = list->num; list->items = realloc (list->items, list->capacity * sizeof (cg_mem_item*)); } free (item); } void cg_destroy_mem_list (cg_mem_list* list) { free (list->items); }
This is how I use it:
// The struct being stored in the list typedef struct some_data_type { CG_ITEMIZABLE int random_data; } some_data_type; int main (void) { // Declare and define the list cg_mem_list data_list; cg_new_mem_list (&data_list, sizeof(some_data_type)); // Allocates a new item and sets it up some_data_type* first_item = (some_data_type*)cg_mem_list_add(&data_list); first_item->random_data = 12; // <More additions and operations> // This frees the item cg_mem_list_remove(&data_list, (cg_mem_item*)&first_item); }
I'd also like to note that I didn't implement any checks malloc
or realloc
because this is in a game-dev-related library, and I figure if it can't allocate any new memory it's probably gonna crash and burn either way. If you have any suggestions for how to gracefully handle this (other than just straight-up throwing an error and aborting, which is pretty much the same as crashing anyways for this sort of application honestly) I'd appreciate it.