c/c++ 单例模式

 

概念

单例模式(Singleton)是一种创建型设计模式, 确保一个类在整个程序中仅存在一个实例, 并提供全局访问点

特点

  • 禁止在类外部直接创建对象

  • 类内部维护唯一实例

  • 提供访问该实例的方法

措施

  • 私有化构造函数

  • 使用静态成员变量存储实例

  • 提供静态成员函数访问实例

graph LR;
    S(单例模式)
    subgraph T[特点]
        A(禁止在类外部创建对象)
        B(类自己内部维护唯一对象)
        C(提供访问该对象方法)
    end
    subgraph R[措施]
        A1(私有化构造函数)
        B1(静态成员变量)
        C1(静态成员函数)
    end
    S-->A-->A1
    S-->B-->B1
    S-->C-->C1

单例模式主要分为两类

graph LR;
    X(分类)
    X-->A(饿汉式)-->A1(无论用不用单例对象, 程序启动即创建)
    X-->B(懒汉式)-->B1(单例对象用时再创建, 不用即销毁)

实现

c

c中可通过静态变量 + malloc 实现懒汉式单例

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int value;
} Singleton;

Singleton* get_instance() {
    static Singleton* s = NULL;
    if (s == NULL) {
        s = (Singleton*)malloc(sizeof(Singleton));
        s->value = 0;
    }
    return s;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();
    printf("s1 address: %p\n", s1);
    printf("s2 address: %p\n", s2);
    return 0;
}

运行结果

s1 address: 0x5affbf72a2a0
s2 address: 0x5affbf72a2a0

说明: 两次获取的地址相同, 仅创建了一次实例

c++

c++ 中可利用局部静态变量实现线程安全单例(c++11 及以上)

#include <iostream>

class Singleton {
public:
    // 返回单例, c++11 以上线程安全
    static Singleton& get_instance() {
        static Singleton s;
        return s;
    }
    // 禁用拷贝构造函数
    Singleton(Singleton const&) = delete;
    // 禁用赋值构造函数
    Singleton& operator=(Singleton const&) = delete;
private:
    // 构造与析构函数设置为私有类型
    Singleton() = default;
    ~Singleton() = default;
};

int main(void) {
    Singleton& s1 = Singleton::get_instance();
    Singleton& s2 = Singleton::get_instance();
    Singleton& s3 = Singleton::get_instance();

    std::cout << &s1 << std::endl;
    std::cout << &s2 << std::endl;
    std::cout << &s3 << std::endl;
    return 0;
}

运行结果

0x604558498151
0x604558498151
0x604558498151

可发现仅执行了一次构造与析构函数, 并且创建出对象地址均一致, 说明为同个对象

单例模板

为了提高复用性, 可以使用模板实现通用单例模式

#include <iostream>

template <typename T>
class Singleton {
public:
    static T& get_instance() {
        static T s;
        return s;
    }

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
protected:
    Singleton() = default;

    virtual ~Singleton() = default;
};

class Log : public Singleton<Log> {
    // 为使父类能访问派生类构造与析构函数
    friend class Singleton<Log>;
public:
    Log(const Log&) = delete;
    Log& operator=(const Log&) = delete;
private:
    Log() = default;
    ~Log() = default;
};