Max*_*Max 5 c error-handling memory-management
给出这样的函数声明:
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, "%s/ping", base_address) < 0) {
MALLOC_ERROR();
}
... do some stuff with base address ...
// release both, as everything worked
free(base_address);
free(ping_url);
}
Run Code Online (Sandbox Code Playgroud)
如果第一次调用base_address成功并且第二次调用asprintf()失败,我该如何干净地跳到函数末尾以便安全地释放已分配的内存?
在没有太多代码重复或goto语句的情况下,如何在一个接一个地分配内存(并且每个分配可能失败)的情况下,是否存在一些标准模式以避免内存泄漏?
不要害怕goto
.它是处理C中异常的最简单,最清晰,最易读的方法:
你不要重复自己.重复的代码容易出错.
您不会创建深层嵌套代码.深嵌套是难以辨认的.
你不躲在do {...} while (0)
及break
.好的代码说出它意味着什么.
这是一个基本的例子:
int operation() {
int result = SUCCESS;
if ((result = may_fail_first()) == FAILURE) {
goto failed_first;
}
if ((result = may_fail_second()) == FAILURE) {
goto failed_second;
}
// If your cleanup code doesn't ordinarily need to run.
goto end;
failed_second:
cleanup_second();
// If you don't need to clean up everything.
goto end;
failed_first:
cleanup_first();
end:
return result;
}
Run Code Online (Sandbox Code Playgroud)
这是goto
错误处理的理想用法之一:
if (base_address(getThis(), 0, &base_address TSRMLS_CC) == FAILURE) {
goto end;
}
if (asprintf(&ping_url, "%s/ping", base_address) < 0) {
goto release_address;
}
// do stuff
release_address:
free(base_address);
end:
Run Code Online (Sandbox Code Playgroud)
这样,您就不必重复相同的释放代码,以防您有许多相互依赖的分配呼叫.
您可能想在此处参考我的另一个答案,其中讨论了一般情况.
小智 2
如果在声明期间将 NULL 分配给指针变量,那么也free
能够处理它们从未被malloc
编辑过的情况(它什么也不做)。(可以使用其他保护,例如 -1 来引用无效的 fd。)
我将其与(附加)清理结合使用goto
——其他一些答案对我来说看起来“冗长”。我发现goto
必须明智地使用它以避免意大利面条式代码,而且一般来说,我发现“gotos around gotos”太难一致地跟踪。首先附加的 NULL 赋值还允许变量本身用作检查保护(在任何可能的清理或其他情况下)。
快乐编码。
例子:
void my_func() {
char *base_address = NULL;
char *ping_url = NULL;
if (base_address(getThis(), 0, &base_address TSRMLS_CC) == FAILURE) {
goto cleanup;
}
if (asprintf(&ping_url, "%s/ping", base_address) < 0) {
goto cleanup;
}
// stuff... and assign return value (or return directly) if applicable,
// assign NULL to variables which contain values that should
// not be free'd, etc (use as guards!).
// I prefer to add guards into the cleanup vs. "skip over it".
// I vary rarely, if ever, have multiple cleanup sections -- in most
// cases this would indicate the need for additional function(s) to me.
cleanup:
free(base_address);
if (ping_url) {
// perhaps need additional cleanup
free(ping_url);
}
// Return value, if applicable. (If a "direct return" above isn't
// advisable for the given function due to cleanup rules.)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
233 次 |
最近记录: |