我试图用C编写一个函数来解决数学问题。在该函数中,有几个步骤,每个步骤都需要分配一些内存,其大小取决于前面步骤中的计算结果(因此,我不能在函数开始时全部分配它们)。伪代码如下所示:

int func(){
    int *p1, *p2, *p3, *p4;
    ...

    p1 = malloc(...);
    if(!p1){
        return -1;            //fail in step 1
    }

    ...
    p2 = malloc(...);
    if(!p2){
        free(p1);
        return -2;            //fail in step 2
    }

    ...
    p3 = malloc(...);
    if(!p3){
        free(p1);
        free(p2);
        return -3;            //fail in step 3
    }

    ...
    p4 = malloc(...);
    if(!p4){
        free(p1);
        free(p2);
        free(p3);            /* I have to write too many "free"s here! */
        return -4;           //fail in step 4
    }

    ...
    free(p1);
    free(p2);
    free(p3);
    free(p4);

    return 0;                //normal exit
}

上述处理malloc故障的方法非常丑陋。因此,我通过以下方式进行操作:
int func(){
    int *p1=NULL, *p2=NULL, *p3=NULL, *p4=NULL;
    int retCode=0;
    ...

    /* other "malloc"s and "if" blocks here */

    ...
    p3 = malloc(...);
    if(!p3){
        retCode = -3;            //fail in step 3
        goto FREE_ALL_EXIT;
    }

    ...
    p4 = malloc(...);
    if(!p4){
        retCode = -4;            //fail in step 4
        goto FREE_ALL_EXIT;
    }

    ...
FREE_ALL_EXIT:
    free(p1);
    free(p2);
    free(p3);
    free(p4);

    return retCode;              //normal exit
}

尽管我认为现在它更加简洁,清晰和美观,但我的队友仍然强烈反对使用“goto”。他提出了以下方法:
int func(){
    int *p1=NULL, *p2=NULL, *p3=NULL, *p4=NULL;
    int retCode=0;
    ...

    do{

        /* other "malloc"s and "if" blocks here */

        p4 = malloc(...);
        if(!p4){
            retCode = -4;            //fail in step 4
            break;
        }

    ...
    }while(0);

    free(p1);
    free(p2);
    free(p3);
    free(p4);

    return retCode;              //normal exit
}

嗯,这似乎是避免使用'goto'的一种方法,但是这种方法会增加缩进量,从而使代码难看。

所以我的问题是,还有其他方法可以以良好的代码风格处理许多“malloc”失败吗?谢谢你们。

最佳答案

询问您的队友他将如何重新编写这种代码:

if (!grabResource1()) goto res1failed;
if (!grabResource2()) goto res2failed;
if (!grabResource3()) goto res3failed;

(do stuff)

res3failed:
releaseResource2();
res2failed:
releaseResource1();
res1failed:
return;

并询问他如何将其推广到n资源。 (在这里,“获取资源”可能意味着锁定互斥锁,打开文件,分配内存等。“NULL上的释放就可以了”黑客无法解决所有问题……)

在这里,goto的替代方法是创建一个嵌套函数链:抢占资源,调用一个获取另一个资源的函数,然后调用另一个获取资源并调用另一个函数的函数...当一个函数失败时,其调用者可以释放它的资源和返回失败,因此释放在堆栈展开时发生。但是您真的认为这比gotos容易阅读吗?

(此外:C++具有构造函数,析构函数和RAII惯用语来处理这类事情。但是在C语言中,这是goto显然是正确答案的一种情况,IMO。)

关于c - 还有其他方法可以处理许多 'malloc'故障吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6755934/

10-11 22:09
查看更多