单例模式

 

概念

单例模式表示只允许存在唯一对象实例

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

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

typedef struct {
    int value;
} Singleton;

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

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

C++

#include <iostream>

class Singleton {
public:
    // 返回单例, C++11 以上线程安全
    static Singleton& GetInstance() {
        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::GetInstance();
    Singleton& s2 = Singleton::GetInstance();
    Singleton& s3 = Singleton::GetInstance();
    std::cout << &s1 << std::endl;
    std::cout << &s2 << std::endl;
    std::cout << &s3 << std::endl;
    return 0;
}

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

单例模板

#include <iostream>

template <typename T>
class Singleton {
public:
    static T& GetInstance() {
        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;
};