我有一段看起来像这样的代码(这只是为了显示结构而简化):
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个,因此该方法变得非常令人毛骨悚然和丑陋。有没有什么好方法,如何在没有过多检查和释放的情况下解决这种模式? (最好的方法是将方法分解为通过检查可以清晰管理的较小部分,但我想因某些原因避免这种情况)
答案 0 :(得分:3)
goto
(以及常见的C惯用语)(IMHO)一个好用:
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;
答案 1 :(得分:1)
处理此问题的最佳方法通常是使用几个内部包装函数。将分配与算法分开。将变量初始化为0(NULL)并利用free(NULL)
作为明确定义的无操作,这意味着无论哪个函数失败,所有内容都将被清除。
static int allocate (type1** X1, type2** X2, type3** X3)
{
*X1 = type1_new(); if(*X1 == NULL) return 0;
*X2 = type2_new(); if(*X2 == NULL) return 0;
*X3 = type3_new(); if(*X3 == NULL) return 0;
return 1;
}
int Ugly_Calculation (void)
{
type1* X1 = 0;
type2* X2 = 0;
type3* X3 = 0;
int result = allocate(&X1, &X2, &X3);
if(result != 0)
{
result = PerformCalculation(X1, X2, X3);
}
free(X1);
free(X2);
free(X3);
return result;
}