top | item 43417320

(no title)

zyedidia | 11 months ago

What is the recommended way to use defer to free values only on an error path (rather than all paths)? Currently I use goto for this:

    void* p1 = malloc(...);
    if (!p1) goto err1;
    void* p2 = malloc(...);
    if (!p2) goto err2;
    void* p3 = malloc(...);
    if (!p3) goto err3;

    return {p1, p2, p3};

    err3: free(p2);
    err2: free(p1);
    err1: return NULL;
With defer I think I would have to use a "success" boolean like this:

    bool success = false;

    void* p1 = malloc(...);
    if (!p1) return NULL;
    defer { if (!success) free(p1) }

    void* p2 = malloc(...);
    if (!p2) return NULL;
    defer { if (!success) free(p2) }

    void* p3 = malloc(...);
    if (!p3) return NULL;
    defer { if (!success) free(p3) }

    success = true;
    return {p1, p2, p3};
I'm not sure if this has really improved things. I do see the use-case for locks and functions that allocate/free together though.

discuss

order

loeg|11 months ago

Can also use a different variable name for the success case and null out any successfully consumed temporaries.

    void* p1 = malloc();
    if (!p1) return failure;
    defer { free(p1); }
    ...
    someOther->pointer = p1;
    p1 = NULL;
    return success;

lelanthran|11 months ago

I don't even bother with `error1`, `error2`, ... `errorN`.

I initialise all pointers to NULL at the top of the function and use `goto cleanup`, which cleans up everything that is not being returned ... because `free(some_ptr)` where `some_ptr` is NULL is perfectly legal.

bobmcnamara|11 months ago

I'm not sure I'd do either for this trivial case, but it might make sense where the cleanup logic is more complex?

    void* p1 = malloc(...);
    void* p2 = malloc(...);
    void* p3 = malloc(...);

    if(p1 && p2 && p3)
      return {p1, p2, p3};

    free(p3);
    free(p2);
    free(p1);
    return NULL;

ayende|11 months ago

That is a well structure system, yes Both cleanup for error and allocation happens in the same place

That means you won't forget to call it, and the success flag is an obvious way to ha dle it