C语言自初始化单例对象实现方案及引用问题咨询
自初始化共享对象实现问题解答
需求与现有代码
我需要实现一个无需外部初始化、可供其他对象调用的共享对象,目前写了如下代码:
头文件(.h)
struct My_Shared_Obj { bool is_happy; struct foo *foos; }; typedef struct My_Shared_Obj *mysharedobj;
源文件(.c)
static mysharedobj MSO = NULL; mysharedobj __instance(); void __mso_do_something(); void __mso_do_something() { mysharedobj _mso = __instance(); // now do something with struct members } mysharedobj __instance() { if(MSO == NULL) { // initialize MSO } return MSO; } // we have an 'API' as follows const struct MSO_API API = { .do_something = &__mso_do_something };
疑问与问题
- 这是否是实现自初始化对象的最佳方式?
- 对对象的修改似乎仅在函数作用域内有效,无法持久到MSO;
另外,同一源文件中还有仅通过API调用的函数,示例代码如下:
static mysharedobj MSO = NULL; /* This method makes an assumption that since it can ever only be called by an API function that the __instance() function has been invoked and that MSO will be a valid object. */ void __foo_add(foo *ptr) { // assume we have next incrementing somewhere MSO->foos[next] = *ptr; } void __mso_do_something() { struct My_Shared_Obj _mso = __instance(); // hypothetical condition; assume we have a function that provides a foo for us... if (!_mso->is_happy) { __foo_add(get_a_foo()); _mso->is_happy = true; } }
目前无法正确引用MSO对象,尝试许久仍未得到预期结果。
编辑说明:已修正部分笔误,本次工作不考虑ISO标准约束。
解答
1. 自初始化对象实现方式的合理性
你当前的思路是懒加载单例模式的典型实现,在不考虑ISO标准约束的前提下,这种方式是可行的,但并非所有场景都适用:
- 优势:仅在首次调用API时初始化对象,节省启动资源;内部封装性强,外部无需感知初始化逻辑。
- 不足:未处理多线程竞态(如果是多线程环境,可能出现多次初始化);
__instance()内的初始化逻辑缺失(仅保留了注释,未实际分配内存和初始化成员)。
如果是单线程、轻量场景,这种方式足够用;复杂场景可调整为:
- 饿汉式初始化:在静态变量定义时直接完成初始化,省去懒加载的判断开销,但会提前占用资源。
- 加锁线程安全:在
__instance()的初始化分支添加互斥锁,避免多线程下的重复初始化。
2. 修改无法持久&MSO引用错误的问题
你的代码存在两个核心错误:
- 结构体拷贝导致修改不持久:
__mso_do_something()中错误地将指针类型mysharedobj赋值给结构体类型struct My_Shared_Obj,这会生成一份结构体副本,后续修改的是副本而非原MSO对象。应改为指针类型接收:mysharedobj _mso = __instance();。 - 重复定义静态变量:补充代码中重复定义了
static mysharedobj MSO = NULL;,同一源文件内的静态变量重复定义会导致编译错误,或运行时使用不同的变量实例,使得__foo_add()引用的MSO与__instance()初始化的MSO不是同一个对象。
修正后的__mso_do_something()代码:
void __mso_do_something() { mysharedobj _mso = __instance(); // 用指针类型接收原对象地址 if (!_mso->is_happy) { __foo_add(get_a_foo()); _mso->is_happy = true; // 直接修改原对象成员,修改会持久化 } }
同时删除补充代码中重复的static mysharedobj MSO = NULL;,确保整个源文件仅存在一个MSO静态变量。
另外,必须补充__instance()的初始化逻辑,否则MSO始终为NULL:
#define MAX_FOOS 10 // 假设定义最大foo数量 mysharedobj __instance() { if(MSO == NULL) { // 分配结构体内存 MSO = malloc(sizeof(struct My_Shared_Obj)); if (MSO == NULL) { return NULL; // 内存分配失败处理 } // 初始化成员 MSO->is_happy = false; MSO->foos = malloc(sizeof(struct foo) * MAX_FOOS); } return MSO; }
内容的提问来源于stack exchange,提问作者IAbstract
相关产品推荐
相关产品推荐

