在具有多个返回点的功能中清理的正确方法

Proper Way to Cleanup in a Function with Multiple Return Points

本文关键字:方法 功能 返回      更新时间:2023-10-16

我有一个递归搜索算法,我想在每次通话后清理指针。但是,我在很多位置返回,在每个人面前放置deletefree似乎很草率。

有更好的方法吗?我是否在函数返回时将它们全部释放,这意味着我应该在堆栈上分配它们,而不是在堆上分配?

请注意,这是一个并行的搜索(未在代码中显示(,但是呼叫者将永远不会在孩子之前返回。这是否还有其他用于使用堆栈的陷阱?

示例代码(不必担心此处的算法(:

//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;
}

这是raii的一小部分:

首先,我们有一个struct,它只是存储您的物品。

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

请注意,在破坏时,free()在这两个项目上都被调用。如何使用它?

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;
}

本地变量faFreeAll类型。当此局部范围范围内时,称为fa的破坏者,它在struct中存储的两个指针上都称为free。还要注意,在返回点上缺少任何代码以释放内存。这将由fa完成范围时完成。

请注意,这是一个简单的例子,没有像其他方法一样具有复杂性,但是它为您提供了RAII范式的基本要素。

但是,我在许多地方返回,在每个人之前放置一个或免费的删除似乎是草率的。

是的。

有更好的方法吗?

是。明智的指针是更好的方法。但是,如果您不想放弃自己正在做的事情,并在继续之前学习如何使用智能指针(可能是第一次很难(继续阅读。

我是否在函数返回时释放它们,这意味着我应该在堆栈上分配它们,而不是在堆上分配?

是的,您可以做到。它的性能也更好。但是,如果您打算分配大量内存,它将无效。

请注意,这是一个并行的搜索(未在代码中显示(,但是呼叫者将永远不会在孩子之前返回。这是否还有其他用于使用堆栈的陷阱?

陷阱是相同的。使用并行代码,您必须小心。

有很多方法可以避免此问题。已经提到了智能指针和堆栈分配。

另一种方法就是只有一个出口。这有时会变得笨拙,因为例如,这意味着您必须在循环中设置一个标志,然后才能突破它,以知道它是成功终止还是由于错误。

另一种方法是在函数A中分配指针,调用函数B进行实际工作(将其传递给分配的指针(,然后一旦函数B返回函数A,释放了指针。

<</p>

scopeguard为您完成工作。

https://en.wikibooks.org/wiki/more_c++; idioms/scope_guard

void your_function()
{
     Scope_guard const final_action = []{
            free(gb);
            free_list(children);};
     // your code here
 };