它是否分析变量的生命周期并简单地将清理函数调用插入到正确的位置?有任何管理费用吗?
我写了两段简单的代码来比较性能,并在没有优化的情况下编译它们。
代码1:
#include <stdio.h>
#include <stdlib.h>
void clean_up(int **final_value)
{
free(*final_value);
}
int main(int argc, char **argv)
{
for (int i = 0; i < 10000000; i++) {
int *avar = malloc(sizeof(int));
clean_up(&avar);
}
return 0;
}
代码2:
#include <stdio.h>
#include <stdlib.h>
void clean_up(int **final_value)
{
free(*final_value);
}
int main(int argc, char **argv)
{
for (int i = 0; i < 10000000; i++) {
int *avar __attribute__ ((__cleanup__(clean_up))) = malloc(sizeof(int));
}
return 0;
}
而且他们的表现也很相似。
您最好进行一些优化编译,特别是如果您想查看生成的汇编代码(使用
gcc -S -fverbose-asm -O
编译)
背后的直觉是,GCC 实际上是所有 C、C++、Ada、Fortran、Go... 的编译器。该属性强制使用与局部变量的 C++ 析构函数相同的内部表示。清理发生在当前块作用域的末尾(例如,在块的右大括号 __attribute__((cleanup))
处)。因此,编译器正在将经过清理的 code2 转换为与 code1 等效的代码。
全局或静态变量的析构函数(在
}
返回后运行)是函数上的 main
(对于插件来说,它们也在
dlclose时间运行)。
因此,要理解这些属性,您最好用 C++ 术语来思考。 我的观点是,如果您需要这些
__attribute__((destructor))
属性,您应该使用 C++ 而不是 C 来编写代码。您的代码将更具可读性并且更少依赖于编译器。我觉得
cleanup
实际上只在生成的 C 代码中有用。我从来没有用过它(感觉当我需要它时,我应该切换到C++)。
当变量超出范围时,将调用清理函数。它并不关心这是否会让其他指针悬空。