sha*_*kin 6 c error-handling coding-style goto flow-control
是的,两个讨厌的结构相结合.它听起来是不是很糟糕,还是被视为控制goto使用的好方法,也提供了合理的清理策略?
在工作中,我们讨论了是否允许在我们的编码标准中使用goto.一般来说,没有人想允许免费使用goto,但有些人对使用它进行清理跳转是积极的.如在此代码中:
void func()
{
char* p1 = malloc(16);
if( !p1 )
goto cleanup;
char* p2 = malloc(16);
if( !p2 )
goto cleanup;
goto norm_cleanup;
err_cleanup:
if( p1 )
free(p1);
if( p2 )
free(p2);
norm_cleanup:
}
Run Code Online (Sandbox Code Playgroud)
这种使用的巨大好处是你不必最终得到这个代码:
void func()
{
char* p1 = malloc(16);
if( !p1 ){
return;
}
char* p2 = malloc(16);
if( !p2 ){
free(p1);
return;
}
char* p3 = malloc(16);
if( !p3 ){
free(p1);
free(p2);
return;
}
}
Run Code Online (Sandbox Code Playgroud)
特别是在具有许多分配的类似构造函数的函数中,这有时会变得非常糟糕,尤其是当有人必须在中间插入某些东西时.
因此,为了能够使用goto,但仍然明确地将其与自由使用隔离,创建了一组流控制宏来处理任务.看起来像这样(简化):
#define FAIL_SECTION_BEGIN int exit_code[GUID] = 0;
#define FAIL_SECTION_DO_EXIT_IF( cond, exitcode ) if(cond){exit_code[GUID] = exitcode; goto exit_label[GUID];}
#define FAIL_SECTION_ERROR_EXIT(code) exit_label[GUID]: if(exit_code[GUID]) int code = exit_code[GUID];else goto end_label[GUID]
#define FAIL_SECTION_END end_label[GUID]:
Run Code Online (Sandbox Code Playgroud)
我们可以使用如下:
int func()
{
char* p1 = NULL;
char* p2 = NULL;
char* p3 = NULL;
FAIL_SECTION_BEGIN
{
p1 = malloc(16);
FAIL_SECTION_DO_EXIT_IF( !p1, -1 );
p2 = malloc(16);
FAIL_SECTION_DO_EXIT_IF( !p2, -1 );
p3 = malloc(16);
FAIL_SECTION_DO_EXIT_IF( !p3, -1 );
}
FAIL_SECTION_ERROR_EXIT( code )
{
if( p3 )
free(p3);
if( p2 )
free(p2);
if( p1 )
free(p1);
return code;
}
FAIL_SECTION_END
return 0;
Run Code Online (Sandbox Code Playgroud)
它看起来不错,并带来许多好处,但是,在将其推广到开发之前,是否有任何我们应该考虑的缺点?毕竟非常流量控制和转到:ish.两人都气馁.在这种情况下,有什么理由阻止他们?
谢谢.
小智 7
这段代码:
void func()
{
char* p1 = malloc(16);
if( !p1 )
goto cleanup;
char* p2 = malloc(16);
if( !p2 )
goto cleanup;
cleanup:
if( p1 )
free(p1);
if( p2 )
free(p2);
}
Run Code Online (Sandbox Code Playgroud)
可以合法地写成:
void func()
{
char* p1 = malloc(16);
char* p2 = malloc(16);
free(p1);
free(p2);
}
Run Code Online (Sandbox Code Playgroud)
内存分配是否成功.
这是有效的,因为如果传递NULL指针,free()不会执行任何操作.在设计自己的API以分配和释放其他资源时,您可以使用相同的习惯用法:
// return handle to new Foo resource, or 0 if allocation failed
FOO_HANDLE AllocFoo();
// release Foo indicated by handle, - do nothing if handle is 0
void ReleaseFoo( FOO_HANDLE h );
Run Code Online (Sandbox Code Playgroud)
像这样设计API可以大大简化资源管理.
| 归档时间: |
|
| 查看次数: |
2426 次 |
| 最近记录: |