如果可能的话,我想将其中一些属性引入我创建的类型中。
更具体地说,我想了解更多有关这些的信息:
我需要前两个的原因是为了实现更好的封装,第三个是为了在发生故障时能够更轻松地编写清理代码。具体来说,如果一个函数在分配可能不同类型的多个资源的过程中失败,我想到的在返回之前释放它们的一种方法不是跟踪程序失败的位置以及失败时分配了哪些资源,而是使用释放/销毁函数,当您调用它们的资源未分配/初始化时,这些函数不会执行任何操作,并且在清理期间对声明的每个对象(可能或可能尚未初始化)调用这些函数。
pthread_mutex_destroy 似乎属于这一类,但如果您在代码顶部将所有要分配的指针分配为 NULL,那么它也是标准的 free。这是处理这个问题的好方法吗?
如果我尝试手动将 any 值分配给
对象,代码怎么可能无法编译?pthread_mutex_t
简单来说,因为编译器不知道
pthread_mutex_t
背后的真实类型。它不会在库标头中导出(pthread.h
),因此它无法“猜测”向其分配其他内容时要做什么。
如果它是作为结构体实现的,为什么我无法访问任何字段?
因为底层的
struct
对你来说是隐藏的,你只能看到库头导出的typedef
。这非常简单,pthread.h
将只包含:
typedef struct some_internal_name pthread_mutex_t;
重要的是,
struct some_internal_name
的定义可供需要访问其字段的库内部部分使用。库用户不会(也不应该)这样做,因此他们不需要结构定义,只看到 typedef
。
我如何可以安全地在未初始化的对象上调用
,并且该调用只会返回错误而不会冒破坏任何内容的风险?pthread_mutex_destroy
man pthread_mutex_destroy.3p
:
如果
的mutex
参数指定的值不是指已初始化的pthread_mutex_destroy()
,则行为未定义。mutex
如果您有执行此操作的代码并且仍然有效,那么这可能只是巧合。事实上,任何类型的未初始化变量都可以保存任何类型的无效数据,因此使用它几乎总是不安全的。在大多数情况下,根据 C 标准这样做也是未定义的行为。唯一的例外是具有
static
存储持续时间的对象,这些对象具有明确定义的行为,因为它们根据定义被清零。
我想在返回之前释放它们的一种方法是不跟踪程序失败的位置以及失败时分配了哪些资源
是的,不幸的是你不能总是释放所有对象(甚至是未初始化的对象)。 C 中有一个使用
goto
标签的常见模式可以帮助您:
void example(void) {
pthread_mutex_t mutex;
FILE *fp;
char *mem;
if (pthread_mutex_init(&mutex, NULL) != 0)
return;
if ((fp = fopen("example.txt", "r")) == NULL)
goto out_destroy_mutex;
if ((mem = malloc(0x100)) == NULL)
goto out_close_file;
/* do whatever you need here */
free(mem);
out_close_file:
fclose(fp);
out_destroy_mutex:
pthread_mutex_destroy(mutex);
return;
}