在 C 中速度超过风格?
Speed over style in C?
可读性和速度哪个更重要?
示例:
假设您在一种方法中创建了很多资源,如果某些操作失败,您必须释放成功创建的资源。您愿意在一般清理标签中执行此操作,该标签将在操作失败后释放任何资源或释放创建的资源吗?
样式一:
void foo(void)
{
void* res1, res2, res3;
res1 = malloc(1);
if(res1 == NULL)
return; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
free(res1);
return;
}
res3 = malloc(1);
if(res3 == NULL)
{
free(res1);
free(res2);
return;
}
}
样式二:
void foo(void)
{
void* res1 = NULL, *res2 = NULL, *res3 = NULL;
res1 = malloc(1);
if(res1 == NULL)
goto lbl_clean_up; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
goto lbl_clean_up;
}
res3 = malloc(1);
if(res3 == NULL)
{
goto lbl_clean_up;
}
lbl_clean_up:
{
if(res1 != NULL)
free(res1);
if(res2 != NULL)
free(res2);
if(res3 != NULL)
free(res3);
return;
}
现在我应该使用样式 1 还是样式 2?样式 2 有更多冗余的 if 语句,但在我看来更具可读性。
我更喜欢第二种方法的变体。使用 goto
跳转到清理代码是一种干净的处理方式。
为了改进这一点,在 NULL 指针上调用 free
是空操作,因此不需要额外的 if
s:
void foo(void)
{
void* res1 = NULL, *res2 = NULL, *res3 = NULL;
res1 = malloc(1);
if(res1 == NULL)
goto lbl_clean_up; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
goto lbl_clean_up;
}
res3 = malloc(1);
if(res3 == NULL)
{
goto lbl_clean_up;
}
lbl_clean_up:
free(res3);
free(res2);
free(res1);
return;
}
按照分配资源的相反顺序释放资源也是一种很好的做法。您可以在使用多个标签时进一步使用它。例如:
void foo(void)
{
FILE *f1, *f2, *f3;
f1 = fopen("infile1", "r");
if (f1 == NULL)
goto cleanup1;
f2 = fopen("infile2", "r");
if (f2 == NULL)
goto cleanup2;
f3 = fopen("outfile", "w");
if (f3 == NULL)
goto cleanup3;
// do something
close(f3);
cleanup3:
close(f2);
cleanup2:
close(f1);
cleanup1:
return;
}
malloc 失败时的速度差异无关紧要。
样式 1 有一个更严重的问题:多个 returns。这样的函数 (IMO) 更难阅读并且更难更改函数 return type
可读性和速度哪个更重要?
示例:
假设您在一种方法中创建了很多资源,如果某些操作失败,您必须释放成功创建的资源。您愿意在一般清理标签中执行此操作,该标签将在操作失败后释放任何资源或释放创建的资源吗?
样式一:
void foo(void)
{
void* res1, res2, res3;
res1 = malloc(1);
if(res1 == NULL)
return; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
free(res1);
return;
}
res3 = malloc(1);
if(res3 == NULL)
{
free(res1);
free(res2);
return;
}
}
样式二:
void foo(void)
{
void* res1 = NULL, *res2 = NULL, *res3 = NULL;
res1 = malloc(1);
if(res1 == NULL)
goto lbl_clean_up; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
goto lbl_clean_up;
}
res3 = malloc(1);
if(res3 == NULL)
{
goto lbl_clean_up;
}
lbl_clean_up:
{
if(res1 != NULL)
free(res1);
if(res2 != NULL)
free(res2);
if(res3 != NULL)
free(res3);
return;
}
现在我应该使用样式 1 还是样式 2?样式 2 有更多冗余的 if 语句,但在我看来更具可读性。
我更喜欢第二种方法的变体。使用 goto
跳转到清理代码是一种干净的处理方式。
为了改进这一点,在 NULL 指针上调用 free
是空操作,因此不需要额外的 if
s:
void foo(void)
{
void* res1 = NULL, *res2 = NULL, *res3 = NULL;
res1 = malloc(1);
if(res1 == NULL)
goto lbl_clean_up; //operation failed
res2 = malloc(1);
if(res2 == NULL)
{
goto lbl_clean_up;
}
res3 = malloc(1);
if(res3 == NULL)
{
goto lbl_clean_up;
}
lbl_clean_up:
free(res3);
free(res2);
free(res1);
return;
}
按照分配资源的相反顺序释放资源也是一种很好的做法。您可以在使用多个标签时进一步使用它。例如:
void foo(void)
{
FILE *f1, *f2, *f3;
f1 = fopen("infile1", "r");
if (f1 == NULL)
goto cleanup1;
f2 = fopen("infile2", "r");
if (f2 == NULL)
goto cleanup2;
f3 = fopen("outfile", "w");
if (f3 == NULL)
goto cleanup3;
// do something
close(f3);
cleanup3:
close(f2);
cleanup2:
close(f1);
cleanup1:
return;
}
malloc 失败时的速度差异无关紧要。
样式 1 有一个更严重的问题:多个 returns。这样的函数 (IMO) 更难阅读并且更难更改函数 return type