Reference counting is a method of managing memory to decrease the risks common memory pitfalls like memory leaks or dangling pointers. Reference counting follows 4 basic rules to perform this
When a reference is passed to a procedure as a parameter, the caller necessarily must maintain it for the duration of the call so the callee doesn't need to call keep_ref, unless the callee saves the pointer somewhere that will outlast the call (ie. a global variable), or the callee returns the pointer to the caller.
When a reference is returned from a procedure, the callee must have a reference to the value which it returns to the caller, when it returns it though it transfers that reference to the caller, it's then the callers responsibility to call free_ref when it no longer needs the reference.
References' stored in local variables necessarily must go away when the procedure returns so the procedure must call free_ref before it returns.
If the struct you're reference counting has a concrete type reference counting can be implemented as follows:
struct buffer *rc_malloc() {
struct buffer *buf = malloc(sizeof(struct buffer));
buf->ref_count = 1;
return buf;
}
void rc_keep_ref(struct buffer *buf) {
buf->ref_count++;
}
void rc_free_ref(struct buffer *buf) {
buf->ref_count--;
if (buf->ref_count == 0) free(buf);
}
A more general method can be used which works for any input type, this is done by reserving 8 bytes before the actual allocated memory for the ref count.
void* rc_malloc(int num_bytes) {
// Add 8 bytes to store the ref_count
int *ref_count = malloc(n+8);
*ref_count = 1;
return ((void*) ref_count) + 8;
}
void rc_keep_ref(void* ptr) {
int *ref_count = ptr - 8;
(*ref_count)++;
}
void rc_free_ref(void* ptr) {
int *ref_count = ptr - 8;
(*ref_count)--;
if (*ref_count == 0) free(ref_count);
}