pointers-memory · intermediate · ~15 min

Reference-counted object lifecycle manager

Implement shared ownership and lifecycle management using reference counts and destructor callbacks.

Challenge

Reference counting is a memory management strategy where an object tracks how many owners hold references to it. When the last reference is released, a destructor callback is automatically executed.

Your Task

Implement:

struct rc_box {
    int ref_count;
    int data;
};

void rc_init(struct rc_box *b, int initial_val);
void rc_retain(struct rc_box *b);
int rc_release(struct rc_box *b, void (*on_destroy)(struct rc_box *));

Rules

  1. rc_init: sets b->ref_count = 1 and b->data = initial_val.
  2. rc_retain: if b != NULL and b->ref_count > 0, increments b->ref_count++.
  3. rc_release:
    • If b == NULL or b->ref_count <= 0, return -1 (invalid/double-release).
    • Decrement b->ref_count--.
    • If b->ref_count == 0: invoke on_destroy(b) (if non-NULL) and return 0.
    • If b->ref_count > 0: return b->ref_count.

Input format

b: pointer to rc_box; initial_val: payload; on_destroy: callback function pointer.

Output format

rc_release returns 0 when destroyed, remaining ref_count when alive, -1 on error.

Constraints

C11 freestanding reference count lifecycle management.

Starter code

#include <stddef.h>

/* The harness provides:
struct rc_box {
    int ref_count;
    int data;
};
*/

void rc_init(struct rc_box *b, int initial_val) {
    (void)b; (void)initial_val;
}

void rc_retain(struct rc_box *b) {
    (void)b;
}

int rc_release(struct rc_box *b, void (*on_destroy)(struct rc_box *)) {
    (void)b; (void)on_destroy;
    return -1;
}

Common mistakes

Decrementing ref_count below zero; calling destructor while references remain.

Edge cases to handle

Calling release when ref_count == 0 returns -1 (double-free prevention); on_destroy NULL is safe.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.