我认为GCC扩展__attribute__((cleanup))
是一个好主意,至少在某些情况下,但我无法弄清楚如何以一种好的方式使用它。我所做的一切看起来仍然很烦人。
我看到很多代码正在执行#define _cleanup_(x) __attribute__((cleanup(x))
只是为了输入更少,但有一种方法可以传递标准函数,如free
或closedir
,fclose
,等?
我认为我不能写:
__attribute__((cleanup(free))) char *foo = malloc(10);
因为清理回调会收到char**
指针,所以我必须总是这样写:
static void free_char(char **ptr) { free(*ptr); }
__cleanup__((free_char)) char *foo = malloc(10);
这很烦人,最令人讨厌的部分是为你需要的所有类型定义这样的清理函数,因为显然你不能只为void **
定义它。避免这些事情的最佳方法是什么?
答案 0 :(得分:10)
您不能编写free
,但不需要为每种类型编写static void cleanup_free(void *p) {
free(*(void**) p);
}
清理函数。这很难看,但你可以这样写:
__attribute__((cleanup))
我第一次看到这个in the systemd
codebase。
对于其他函数,您通常需要编写一个带有额外级别间接的包装器,以便与systemd
一起使用。 #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
func(*p); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
defines a helper macro for this:
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
#define _cleanup_pclose_ __attribute__((cleanup(pclosep)))
使用all over the place,例如
{{1}}
答案 1 :(得分:10)
这里有一个库,可以在unique_ptr
shared_ptr
之上构建通用智能指针(__attribute__((cleanup))
和#include <stdio.h>
#include <csptr/smart_ptr.h>
#include <csptr/array.h>
void print_int(void *ptr, void *meta) {
(void) meta;
// ptr points to the current element
// meta points to the array metadata (global to the array), if any.
printf("%d\n", *(int*) ptr);
}
int main(void) {
// Destructors for array types are run on every element of the
// array before destruction.
smart int *ints = unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int);
// ints == {5, 4, 3, 2, 1}
// Smart arrays are length-aware
for (size_t i = 0; i < array_length(ints); ++i) {
ints[i] = i + 1;
}
// ints == {1, 2, 3, 4, 5}
return 0;
}
):https://github.com/Snaipe/libcsptr
它允许您编写更高级别的代码:
open()
至于惯用语吗?那么上面肯定接近惯用的C ++。不是那么多。 GCC和Clang显然主要支持该功能,因为它们也有C ++编译器,所以他们可以选择在C前端使用RAII机器而无需额外费用。以这种方式编写C-as-as-C并不是一个好主意。它有点依赖于C ++编译器 present ,尽管实际上并没有使用。
如果是我,我可能会调查实现自动释放池,或类似的事情,可以在语言级别的纯C中实际完成。取决于您需要多快地释放资源;对于记忆,你通常可以在没有立即清理的情况下生活。