如何在C中创建Singleton?

Lir*_*evi 25 c singleton design-patterns

在C中创建单例的最佳方法是什么?并发解决方案会很好.

我知道C不是你用于单身人士的第一种语言.

dir*_*tly 30

首先,C不适合OO编程.如果你这样做,你会一直在战斗.其次,单例只是具有一些封装的静态变量.所以你可以使用静态全局变量.然而,全局变量通常具有与其相关的太多弊病.否则你可以使用函数本地静态变量,如下所示:

 int *SingletonInt() {
     static int instance = 42;
     return &instance;
 }
Run Code Online (Sandbox Code Playgroud)

或更聪明的宏:

#define SINGLETON(t, inst, init) t* Singleton_##t() { \
                 static t inst = init;               \
                 return &inst;                       \
                }

#include <stdio.h>  

/* actual definition */
SINGLETON(float, finst, 4.2);

int main() {
    printf("%f\n", *(Singleton_float()));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

最后,请记住,单身人士大多被滥用.很难让它们正确,尤其是在多线程环境下......

  • C非常适合OOP.事实上,真正帮助OOP的C++的唯一特性是语法糖. (4认同)
  • 我并不否认这可以做到,但不能花费大量的时间和精力.例如:使用宏来破解多态函数是一种可行的方法 - 但是你失去了类型安全性.C中也没有RTTI.(是的,C确实具有有限的多态性,想到运算符+, - 等) (2认同)

Ada*_*icz 19

你不需要.C已经有全局变量,所以你不需要一个解决方法来模拟它们.

  • C++是一种面向对象的语言; C不是.当然,你可以*在C中做OOP,但它很难看,很丑陋,而且很难处理.同样,你*可以*在C++中编写几乎-C,但那你为什么要使用C++?所以真的,只需使用全局.尝试通过使用一堆函数本地静态变量和预处理器宏来模糊它来伪装你正在做的事情是没有意义的. (4认同)

jus*_*nhj 14

它几乎和C++版本一样.只需要一个返回实例指针的函数.它可以是函数内部的静态变量.根据平台,使用临界区或pthread互斥体包裹功能体.

#include <stdlib.h>

struct A
{
    int a;
    int b;
};

struct A* getObject()
{
    static struct A *instance = NULL;

    // do lock here
    if(instance == NULL)
    {
        instance = malloc(sizeof(*instance));
        instance->a = 1;
        instance->b = 2;
    }
    // do unlock

    return instance;
};
Run Code Online (Sandbox Code Playgroud)

请注意,您还需要一个函数来释放单例.特别是如果它抓取任何未在进程退出时自动释放的系统资源.


Mic*_*ael 5

编辑:我的回答假设你正在创建的单身人士有点复杂,并且有一个多步创建过程.如果它只是静态数据,请像其他人建议的那样使用全局数据.

C中的单身人士会非常奇怪...我从来没有见过一个看起来特别优雅的"面向对象的C"的例子.如果可能,请考虑使用C++.C++允许您选择要使用的功能,许多人只是将它用作"更好的C".

下面是一个非常典型的无锁一次性初始化模式.如果前一个为null,则InterlockCompareExchangePtr以新的值原子交换.这可以保护多个线程同时尝试创建单例,只有一个会获胜.其他人将删除他们新创建的对象.

MyObj* g_singleton; // MyObj is some struct.

MyObj* GetMyObj()
{
    MyObj* singleton;
    if (g_singleton == NULL)
    {
        singleton = CreateNewObj();

        // Only swap if the existing value is null.  If not on Windows,
        // use whatever compare and swap your platform provides.
        if (InterlockCompareExchangePtr(&g_singleton, singleton, NULL) != NULL)
        {
              DeleteObj(singleton);
        }
    }

    return g_singleton;
}

DoSomethingWithSingleton(GetMyObj());
Run Code Online (Sandbox Code Playgroud)