In order to concisify the handling of a failed call to malloc
, realloc
, or calloc
, I have made a few files to dictate "safe" memory management. This is part of my project stac
, so the prefix will appear in the following code snippets. Further, I have made the decision to use snake_case
as opposed to standard camelCase
.
What I hope to get out of this, and questions I have: are these functions in bad practice? Is there a different way I should be handling failed calls to memory allocators? And is there anything particularly wrong with the code I have written?
safe_mem.c
#include "safe_mem.h"
void* safe_malloc(size_t size){
void* memory = malloc(size);
if(memory == NULL){
free(memory);
runtime_error("failed to allocate memory.");
}
return memory;
}
void* safe_calloc(size_t num, size_t size){
void* memory = calloc(num, size);
if(memory == NULL){
free(memory);
runtime_error("failed to allocate memory.");
}
return memory;
}
void* safe_realloc(void* ptr, size_t size){
void* memory = realloc(ptr, size);
if(memory == NULL){
free(memory);
runtime_error("failed to reallocate memory.");
}
return memory;
}
safe_mem.h
#ifndef STAC_SAFE_MEM
#define STAC_SAFE_MEM
#include <stdio.h>
#include <stdlib.h>
#include "error.h"
void* safe_malloc(size_t);
void* safe_calloc(size_t, size_t);
void* safe_realloc(void*, size_t);
#endif
error.c
#include "error.h"
void make_error(char* type, char* message){
eprintf("%s error: %s\n", type, message);
}
void fatal_error(char* type, char* message, int exit_code){
make_error(type, message);
exit(exit_code);
}
void runtime_error(char* message){
fatal_error("Runtime", message, STATUS_RUNTIME_ERROR);
}
void generic_error(char* message){
fatal_error("Generic", message, STATUS_GENERIC_ERROR);
}
error.h
#ifndef STAC_ERROR
#define STAC_ERROR
#include <stdio.h>
#include <stdlib.h>
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define STATUS_OKAY (0)
#define STATUS_RUNTIME_ERROR (1)
#define STATUS_GENERIC_ERROR (-1)
void make_error(char*, char*);
void fatal_error(char*, char*, int);
void runtime_error(char*);
void generic_error(char*);
#endif
free
ing memory that couldn't be allocated in all your allocation calls - Althoughfree
ing a NULL pointer doesn't normally hurt, it also doesn't do anything \$\endgroup\$namespace std
... \$\endgroup\$NULL
- and that's patently not the case for many programs.malloc_or_die()
(and similar) would be much more honest! \$\endgroup\$