You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:08:10