bod*_*ydo 16 c memory free allocation
假设我非常防御地编写代码,并且总是从我调用的所有函数中检查返回类型.
所以我喜欢:
char* function() {
char* mem = get_memory(100); // first allocation
if (!mem) return NULL;
struct binder* b = get_binder('regular binder'); // second allocation
if (!b) {
free(mem);
return NULL;
}
struct file* f = mk_file(); // third allocation
if (!f) {
free(mem);
free_binder(b);
return NULL;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
注意free()事情失控的速度有多快.如果某些功能失败,我必须先释放每一个分配.代码很快变得丑陋,我所做的就是复制粘贴一切.我成为了一个复制/粘贴程序员,更糟糕的是,如果有人在其间添加一个声明,他必须修改下面的所有代码来调用free()他的添加.
经验丰富的C程序员如何解决这个问题?我无法解决任何问题.
谢谢,Boda Cydo.
kar*_*lip 35
您可以定义一个可以释放资源的新标签,然后您可以在代码失败时进行GOTO.
char* function()
{
char* retval = NULL;
char* mem = get_memory(100); // first allocation
if (!mem)
goto out_error;
struct binder* b = get_binder('regular binder'); // second allocation
if (!b)
goto out_error_mem;
struct file* f = mk_file(); // third allocation
if (!f)
goto out_error_b;
/* ... Normal code path ... */
retval = good_value;
out_error_b:
free_binder(b);
out_error_mem:
free(mem);
out_error:
return retval;
}
Run Code Online (Sandbox Code Playgroud)
这里已经讨论了使用GOTO 进行错误管理:在C中有效使用goto进行错误管理?
我知道我会因此而被私刑,但我有一位朋友说他们已经习惯goto了.
然后他告诉我,在大多数情况下这还不够,他现在用setjmp()/ longjmp().基本上他重新发明了C++的例外但却不那么优雅.
也就是说,既然goto 可以工作,你可以将它重构为不使用的东西goto,但缩进会快速失控:
char* function() {
char* result = NULL;
char* mem = get_memory(100);
if(mem) {
struct binder* b = get_binder('regular binder');
if(b) {
struct file* f = mk_file();
if (f) {
// ...
}
free(b);
}
free(mem);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
顺便说一下,在块周围散布局部变量声明就像那不是标准C.
现在,如果你意识到free(NULL);C标准定义为无效,你可以简化一些嵌套:
char* function() {
char* result = NULL;
char* mem = get_memory(100);
struct binder* b = get_binder('regular binder');
struct file* f = mk_file();
if (mem && b && f) {
// ...
}
free(f);
free(b);
free(mem);
return result;
}
Run Code Online (Sandbox Code Playgroud)
虽然我很佩服你的防御编码方法,这是一件好事.每个C程序员都应该有这种心态,它也适用于其他语言......
我不得不说这是关于GOTO的一件有用的东西,尽管纯粹主义者会另有说法,这将是一个相当于一个终极块,但有一个特别的问题,我可以在那里看到......
karlphillip的代码几乎完成但是....假设函数是这样完成的
char* function() {
struct file* f = mk_file(); // third allocation
if (!f) goto release_resources;
// DO WHATEVER YOU HAVE TO DO....
return some_ptr;
release_resources:
free(mem);
free_binder(b);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
小心!!!这将取决于你认为合适的功能的设计和目的,放在一边..如果你从这样的功能返回,你可能最终落在release_resources标签....这可能会导致一个微妙的错误,所有对堆上指针的引用都消失了,最终可能会返回垃圾...所以请确保如果已分配内存并将其返回,请return在标签前使用关键字,否则内存可能会消失.或者创建内存泄漏....