当前位置:编程学习 > C/C++ >>

重构C资源释放代码

今天我在维护一个C项目的时候发现有的函数内部有很多的return语句,每个return前面都有一段相同的资源释放的代码。代码看起来就像这样:

int f() {
    char *p1 = (char*)malloc(1024 * sizeof(char));


    int *p2 = (int*)malloc(10 * sizeof(int));


    ...

    if (...) {

        free(p1);


        free(p2);


        return 1;


    }

    for (...) {


        if (...) {

            free(p1);


            free(p2);


            return 2; 

        }


    }


    ...


    free(p1);

    free(p2);


    return 0;


}

 

上面的代码资源释放部分重复度太高,读起来不够清爽。更重要的是如果某一个return之前忘记了释放资源就会发生内存泄露,只能靠程序的作者和维护者随时提高警惕。这类问题在C++中可以通过RAII来很好地解决,但可惜C语言没有自动析构机制,所以,我们需要通过一些技巧来达到类似的效果。看下面的代码:
 

int void f() {

    int return_code = 0;


    char *p1 = (char*)malloc(1024 * sizeof(char));


    int *p2 = (int*)malloc(10 * sizeof(int));


    ...

    if (...) {

        return_code = 1;


        goto _END_F;

    }

    for (...) {


        if (...) {

            return_code = 2;
            goto _END_F;


        }

    }


    ...


_END_F:


    free(p1);

    free(p2);


    return return_code;


}

 

我们把资源释放代码统一放在函数末尾,并打上_END_F标签,把原来return的地方用goto _END_F替换。我们通过这种方式消除了资源释放部分的冗余代码,也一定程度上减小了忘记释放资源的风险。不过,由于现在需要每次在goto前面加上return_code=x,还是有一定的冗余和遗忘的危险。于是,我们可以通过下面的宏可以进一步完善:

#define RETURN(label, returnCode) { return_code = returnCode; goto label;}


这样我们就可以用RETURN(_END_F, 2)来一并实现设置返回值和goto的效果了,即简化了代码,又防止忘记设置返回值。 最终重构效果如下:


 

#define RETURN(label, returnCode) { return_code = returnCode; goto label;}

int void f() {

    int return_code = 0;


    char *p1 = (char*)malloc(1024 * sizeof(char));


    int *p2 = (int*)malloc(10 * sizeof(int));


    ...

    if (...) {

        RETURN(_END_F, 1);


    }

    for (...) {


        if (...) {


            RETURN(_END_F, 2);

        }

    }


    ...


_END_F:


    free(p1);

    free(p2);


    return return_code;


}

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,