这个问题实际上是不久前在programming.reddit.com 上进行有趣讨论的结果.它基本归结为以下代码:
int foo(int bar)
{
int return_value = 0;
if (!do_something( bar )) {
goto error_1;
}
if (!init_stuff( bar )) {
goto error_2;
}
if (!prepare_stuff( bar )) {
goto error_3;
}
return_value = do_the_thing( bar );
error_3:
cleanup_3();
error_2:
cleanup_2();
error_1:
cleanup_1();
return return_value;
}
Run Code Online (Sandbox Code Playgroud)
goto这里的使用似乎是最好的方法,导致所有可能性中最干净,最有效的代码,或者至少在我看来.在Code Complete中引用Steve McConnell :
goto在分配资源,对这些资源执行操作,然后释放资源的例程中很有用.使用goto,您可以清理代码的一部分.goto可以降低忘记在检测到错误的每个位置释放资源的可能性.
此方法的另一个支持来自本节中的" Linux设备驱动程序"一书.
你怎么看?这种情况goto在C中是否有效?您是否更喜欢其他方法,这些方法会产生更复杂和/或效率更低的代码,但是要避免goto?
我正在开展一个学校项目,老师要求我们在项目终止时释放所有资源。
我正在努力寻找一种方法来编写更具可读性和/或更少的代码来管理它,特别是考虑到不同的退出点可能会释放不同的资源集,这使得这变得更加复杂。
最简单和最混乱的解决方案似乎是这样的(退出点表示为返回 -1 的“some_sys_call”调用):
char *a = malloc(1);
if(some_sys_call() == -1){
free(a);
return -1;
}
//b is needed until the end
char *b = malloc(1);
if(some_sys_call() == -1){
free(a);
free(b);
return -1;
}
//c is needed until the end
char *c = malloc(1);
//a is no longer needed from here on, so it's freed right away
free(a);
if(some_sys_call() == -1){
free(b);
free(c);
return -1;
}
//Exit point when there are no errors
free(b);
free(c);
return 0;
Run Code Online (Sandbox Code Playgroud)
由于显而易见的原因,这似乎不太吸引人:您需要编写大量代码,尤其是当您拥有大量资源时,这会导致代码因释放而变得臃肿且可读性较差。当然,您不能简单地编写一个宏或函数来释放所有资源并在每个退出点调用它,如下所示:
#define free_all …Run Code Online (Sandbox Code Playgroud) 给出这样的函数声明:
int base_address(zval *object, int add_prefix, char **base_address TSRMLS_DC) {
int result;
char *host;
long port;
char *prefix;
host = ... get host from object ...;
port = ... get port from object ...;
prefix = ... get prefix from object ...;
result = SUCCESS;
if (asprintf(base_address, "%s:%ld/%s", host, port, prefix) < 0) {
result = FAILURE;
}
return result;
}
void my_func() {
char *base_address;
char *ping_url;
if (base_address(getThis(), 0, &base_address TSRMLS_CC) == FAILURE) {
MALLOC_ERROR();
}
if (asprintf(&ping_url, …Run Code Online (Sandbox Code Playgroud)