Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper Way to Cleanup in a Function with Multiple Return Points

I have a recursive search algorithm, and I want to clean up my pointers after each call. However, I return in so many locations, it seems sloppy to put a delete or free before every one.

Is there a better way? Does me freeing them all at return of the function mean I should just allocate them on the stack instead of in the heap?

Note this is a parallel search (not shown in code), but the caller will never return before its children. Does this have any additional pitfalls for using the stack?

Example Code (Don't worry about the algorithm here):

//create a new struct state (using new), initialize and return (C style)
new_state()

free_list(state* node)//free a list

double minimax(state* node, state* bestState) {

    if (base_case) {
        return;
    }

    state* gb = new_state(); //single node
    state* children = new_state(); //head of list

    generate_children(children); //fill list

    state* current = children; //traverse node

    //recurse on child
    double result = -minimax(current, gb);

    if (case1) {
        free(gb);
        free_list(children);
        return;
    }
    if (case2)  {
        //do stuff
    }

    while(current != NULL){
        result = -minimax(current, gb);
        if (case1) {
            free(gb);
            free_list(children);
            return;
        }
        if (case2)  {
            //do stuff
        }
        current = current->next;
    }
    free(gb);
    gb = NULL;

    //More stuff (with children but not gb)
    free_list(children);
    return;
}
like image 566
River Avatar asked Sep 18 '25 21:09

River


1 Answers

Here is a small sample of RAII:

First we have a struct that simply stores your items.

struct FreeAll
{
    state* gb;
    state* children;
    FreeAll(state* g, state* c) : gb(g), children(c) {}
    ~FreeAll() { free(gb); free(children); }
};

Note that on destruction, the free() is called on both items. How to use it?

double minimax(state* node, state* bestState) 
{
    if (base_case) {
        return;
    }

    state* gb = new_state(); //single node
    state* children = new_state(); //head of list

    // Initialize our small RAII object with the above 
    // pointers   
    FreeAll fa(gb, children);

    generate_children(children); //fill list
    state* current = children; //traverse node
    //recurse on child
    double result = -minimax(current, gb);

    if (case1) {
        return;
    }
    if (case2)  {
        //do stuff
    }

    while(current != NULL){
        result = -minimax(current, gb);
        if (case1) {
            return;
        }
        if (case2)  {
            //do stuff
        }
        current = current->next;
    }
    //More stuff (with children but not gb
    return;
}

The local variable fa is a FreeAll type. When this local goes out of scope, the destructor of fa is called which calls free on both the pointers that were stored in the struct. Also note the lack of any code at the return points to free the memory. This will be done by fa when it goes out of scope.

Note this is a simple example, and has none of the sophistication as other methods mentioned, but it gives you the basic gist of the RAII paradigm.

like image 174
PaulMcKenzie Avatar answered Sep 20 '25 11:09

PaulMcKenzie