c - 可能会失败的分配和操作顺序的正确模式

标签 c design-patterns

我有一段代码看起来几乎像这样(这被简化只是为了显示结构):

int Ugly_Calculation(void)
{
    type1 *X1 = type1_new();
    if (!X1) return 0;
    type2 *X2 = type2_new(X1);
    if (!X2) return 0;
    type3 *X3 = type3_new(X1, X2);
    if (!X3) return 0;
    int result = PerformCalculation(X1, X2, X3);
    free(X3);
    free(X2);
    free(X1);
    return result;
}

它分配一些对象并将它们用于某些计算并释放对象。 typeX_new 函数经常返回零,因此内存通常没有被正确释放。

在我的第一次迭代中,我按以下方式重写了代码:

typedef struct
{
    type1 *X1;
    type2 *X2;
    type3 *X3;
} ugly_context;

void free_ctx(ugly_context *ctx)
{
    free(ctx->X1);
    free(ctx->X2);
    free(ctx->X3);
}

int Ugly_Calculation(void)
{
    ugly_context ctx = {NULL, NULL, NULL};

    ctx->X1 = type1_new();
    if (!ctx->X1)
    {
        free_ctx(&ctx);
        return 0;
    }
    ctx->X2 = type1_new(ctx->X1);
    if (!ctx->X2)
    {
        free_ctx(&ctx);
        return 0;
    }
    ctx->X3 = type1_new(ctx->X1, ctx->X2);
    if (!ctx->X3)
    {
        free_ctx(&ctx);
        return 0;
    }
    int result = PerformCalculation(X1, X2, X3);
    free_ctx(&ctx);
    return result; 
}

我的第一个修复是安全的,但它失去了原始代码的可读性。 我的第二个想法如下:

type2 *type2_new_check(type1 *X1)
{
   type2 *result = NULL;
   if (X1)
   {
       result = type2_new(X1);
   }
   return result;
}

type3 *type3_new_check(type1 *X1, type2 *X2)
{
   type3 *result = NULL;
   if (X1 && X2)
   {
       result = type3_new(X1, X2);
   }
   return result;
}

int PerformCalculation_check(type1 *X1, type2 *X2, type3 *X3)
{
    int result = 0;
    if (X1 && X2 && X3)
    {
       result = PerformCalculation(X1, X2, X3);
    }
    return result;
}

int Ugly_Calculation(void)
{
    type1 *X1 = type1_new();
    type2 *X2 = type2_new_check(X1);
    type3 *X3 = type3_new_check(X1, X2);
    int result = PerformCalculation_check(X1, X2, X3);
    free(X3);
    free(X2);
    free(X1);
    return result;
}

代码可读性还可以,早期退出也没有了,但是对于有 3 个内存块的方法来说它相当长。

我的真实代码不是 3 次分配,而是 15 次分配,因此该方法变得非常令人毛骨悚然和丑陋。有什么好的方法,如何在不进行过多检查和释放的情况下解决这种模式? (最好的方法是将方法分解为更小的部分,这些部分可以通过检查清楚地管理,但出于某种原因我想避免这种情况)

最佳答案

这是 goto 的(恕我直言)一个很好的用途(和一个常见的 C 习语):

    type *obj1 = 0;
    type *obj2 = 0;
    type *obj3 = 0;

    if (!(obj1 = create1())) goto error;
    if (!(obj2 = create2())) goto error;
    if (!(obj3 = create3())) goto error;

    // your logic here

    return 0; // success

error:
    free(obj3);
    free(obj2);
    free(obj1);
    return -1; // failure

或者,如果您还需要在成功案例中释放分配的资源,如下所示:

    type *obj1 = 0;
    type *obj2 = 0;
    type *obj3 = 0;
    int success = -1;

    if (!(obj1 = create1())) goto error;
    if (!(obj2 = create2())) goto error;
    if (!(obj3 = create3())) goto error;

    success = 0; // success

    // your logic here

error:
    free(obj3);
    free(obj2);
    free(obj1);
    return success;

关于c - 可能会失败的分配和操作顺序的正确模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45715762/

相关文章:

java - 验证输入并相应执行操作

java - 我如何在Java项目上使用“C”代码?

c - 如果一个字符串是其他字符串的旋转。所有测试用例未运行

C 输入作业

c++ - 为什么 C++ 对函数原型(prototype)(签名)的前向声明更加严格?

c# - 限制对特定程序集的访问

c - Scanf 不接受第二个字符字符串

java - DTO 的设计模式

c# - 开源.Net项目中使用的设计模式示例

Objective-C - !!BOOL 有益