C中单个函数中处理多个malloc错误的推荐方法
建议用什么方法来处理多个malloc错误,这些错误可能会在下面的代码中顺序发生C中单个函数中处理多个malloc错误的推荐方法,c,error-handling,malloc,C,Error Handling,Malloc,建议用什么方法来处理多个malloc错误,这些错误可能会在下面的代码中顺序发生 bool myFunc(int x, int y) { int *pBufX = null; int *pBufY = null; if((x <= 0) || (y <= 0)) { return false; } pBufX = (int*)malloc(sizeof(int) * x); if(pBufX == null)
bool myFunc(int x, int y)
{
int *pBufX = null;
int *pBufY = null;
if((x <= 0) || (y <= 0))
{
return false;
}
pBufX = (int*)malloc(sizeof(int) * x);
if(pBufX == null)
{
return false;
}
pBufY = (int*)malloc(sizeof(int) * y);
if(pBufY == null)
{
free(pBufX) //free the previously allocated pBufX
return false;
}
//do something useful
free(pBufX);
free(pBufY);
return true;
}
boolmyfunc(整数x,整数y)
{
int*pBufX=null;
int*pBufY=null;
如果((x个人而言,我更喜欢使用goto。但是,由于免费(NULL)
是安全的,您通常可以提前完成所有分配:
int *a = NULL;
int *b = NULL;
a = malloc( sizeof *a * x);
b = malloc( sizeof *b * y);
if( a == NULL || b == NULL ) {
free(a);
free(b);
return false;
}
如果您需要分配的内存来进行计算以获得进一步分配所需的大小,那么您的函数可能非常复杂,因此无论如何都应该对其进行重构。这是一种可能的解决方案:
bool myFunc(int x, int y)
{
int returnvalue = false;
int *pBufX = NULL; // << null -> NULL
int *pBufY = NULL;
if((x <= 0) || (y <= 0))
{
goto fail;
}
pBufX = (int*)malloc(sizeof(int) * x);
if(pBufX == null)
{
goto fail;
}
pBufY = (int*)malloc(sizeof(int) * y);
if(pBufY == null)
{
goto fail;
}
//do something useful
returnvalue = true;
fail:
free(pBufX); // <<< free(x) -> free(pBufX)
free(pBufY); // <<< free(y) -> free(pBufY)
return returnvalue;
}
可替换为:
free(pBufY);
在我看来,最合适的方法是将核心功能移动到单独的功能:
inline bool doStuff (int x, int y, int* pBufX, int* pBufy)
bool myFunc (int x, int y)
{
bool result;
int *pBufX = NULL;
int *pBufY = NULL;
/* do allocations here if possible */
result = doStuff(x, y, pBufX, pBufY); // actual algorithm
free(pBufX);
free(pBufY);
return result;
}
现在,您只需要在出错时从doStuff
返回,而不必担心释放。理想情况下,您可以在包装函数中执行malloc,从而将内存分配与实际算法分离,但有时这是不可能的
注意,free保证在您向它传递空指针时它不会做任何事情
编辑:
请注意,如果您在doStuff
中进行分配,您需要将指针传递给指针!这是一个很好的问题!(我想我会发现一个重复的问题,但不,奇怪的是,C中如此重要的一个方面似乎以前从未真正提出过)
我发现有两个问题涉及这一领域的一些方面:
这些主要集中在转到方式上。所以首先让我们讨论一下
转到方式
如果您有一个依赖于分配若干资源的代码,这些资源必须在以后发布,那么您可以使用如下模式:
int function(void){
res_type_1 *resource1;
res_type_2 *resource2;
resource1 = allocate_res_type_1();
if (resource1 == NULL){ goto fail1; }
resource2 = allocate_res_type_2();
if (resource2 == NULL){ goto fail2; }
/* Main logic, may have failure exits to fail3 */
return SUCCESS;
fail3:
free_res_type_2(resource2);
fail2:
free_res_type_1(resource1);
fail1:
return FAIL;
}
您可以在优秀的Regehr博客上阅读更多关于这种方法的内容:还可以指向经常使用这种模式的Linux内核本身
箭头代码
这是另一种可能的方法之一。上面的示例与“箭头”模式类似:
模式得名的一个明显问题是潜在的深层嵌套(代码看起来像箭头),为什么这个模式不那么受欢迎
其他方式
关于分配和释放资源的要求,我想不出多少(除了您在问题中详述的标记变量)。当您没有此类约束时,您会有更多的自由,您可以在其他问题和答案中看到一些很好的方法
如果资源彼此不依赖,您也可以使用其他模式(例如第一个代码示例提供的早期返回),但是如果您需要,这两种模式可以正确处理资源依赖性(即,资源2只能在有效资源1的基础上分配),如果给定资源的空闲函数没有处理失败的分配返回。这是极少数情况下,goto
非常有用的情况之一。只是脱离主题-不要free
x
和y
它们不是分配内存的指针。抱歉!想键入pBufX和pBufY。我的错。忽略all模糊处理的变体,比如你的第二个例子,这里只有3种非条件分支的合理方式,你可以使用:从函数返回(丑陋)、转到失败(丑陋)和循环+中断(丑陋)。我选择最不丑陋的。我明白了。忘了你可以用泛型free()释放空指针。我们的代码所使用的内存管理器中不允许使用。虽然此解决方案还可以(尽管它是80年代基础编程中的设计模式:)),我相信从函数返回会更干净。理想情况下,如果可能的话,您可以将内存分配从实际算法中分离出来,以便调用者处理所有问题allocation@nushydude如果您的库不允许使用免费(NUL)
(顺便说一句,这绝对是非标准的),然后您可以将此行为封装在一个忽略空指针的myfree
函数中。@Lundin是的,我相信该函数可以设计为永远不会出现此问题。遗憾的是,这是针对新项目的。如果您提前进行分配,您可以使用int*a=malloc(sizeof(*a)*x);int*b=malloc sizeof(*b)*y)
而不是显式地设置为null然后赋值。编译器可能会这样做,所以这并不重要。我同意重构评论。遗憾的是,我习惯了我们使用的内存管理器的操作方式。它无法释放null指针(给出断言)所以我们必须在释放之前检查空指针,因此我们总是将它们初始化为空,然后开始我们的工作。我刚刚为这个例子编写了malloc和free。是的,编译器应该对它们进行优化。只是让我们的代码更长。
inline bool doStuff (int x, int y, int* pBufX, int* pBufy)
bool myFunc (int x, int y)
{
bool result;
int *pBufX = NULL;
int *pBufY = NULL;
/* do allocations here if possible */
result = doStuff(x, y, pBufX, pBufY); // actual algorithm
free(pBufX);
free(pBufY);
return result;
}
int function(void){
res_type_1 *resource1;
res_type_2 *resource2;
resource1 = allocate_res_type_1();
if (resource1 == NULL){ goto fail1; }
resource2 = allocate_res_type_2();
if (resource2 == NULL){ goto fail2; }
/* Main logic, may have failure exits to fail3 */
return SUCCESS;
fail3:
free_res_type_2(resource2);
fail2:
free_res_type_1(resource1);
fail1:
return FAIL;
}
int function(void){
res_type_1 *resource1;
res_type_2 *resource2;
int ret = FAIL;
resource1 = allocate_res_type_1();
if (resource1 != NULL){
resource2 = allocate_res_type_2();
if (resource2 != NULL){
/* Main logic, should set ret = SUCCESS; if succeeds */
free_res_type_2(resource2);
}
free_res_type_1(resource1);
}
return ret;
}