Skip to content

单例模式

需要把构造函数私有化,这样就无法在类外创建实例。

1
2
3
int main() {
    Singleton obj; // 错误:Singleton的构造函数是私有的
}
但是可以 Singleton* Singleton::instance = new Singleton();,虽然构造函数是私有的,但它在Singleton类内部是可访问的。 当你在类的成员函数或者静态成员初始化中调用这个构造函数时,你实际上仍然处于类的“内部”范围。这就是为什么new Singleton();是合法的。在这里,Singleton::instance的初始化发生在类的“内部”,因此可以调用私有的构造函数。这与在类的外部尝试直接创建对象(如Singleton obj;)是不同的

恶汉模式:

饿汉模式是指在程序启动时就创建单例对象,也就是将单例对象定义为静态成员变量,并在定义时直接初始化。实现饿汉模式的关键在于将构造函数声明为私有,这样就无法在类外创建实例。

缺点:饿汉模式的缺点在于无法控制单例对象的创建时间,可能会导致程序启动较慢 优点:线程安全

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Singleton {
public:
    static Singleton* getInstance() {
        return instance;
    }
private:
    Singleton() {} // 将构造函数声明为私有
    static Singleton* instance; // 定义为静态成员变量并直接初始化
};
Singleton* Singleton::instance = new Singleton(); // 直接初始化单例对象

int main() {
    Singleton* obj1 = Singleton::getInstance();
    Singleton* obj2 = Singleton::getInstance();
    // obj1和obj2指向同一个单例对象
    return 0;
}

懒汉模式:

懒汉模式是指在需要时才创建实例,也就是在第一次调用getInstance()方法时创建单例对象。实现懒汉模式的关键在于将构造函数声明为私有,这样就无法在类外创建实例,然后使用静态成员变量保存单例对象的指针,通过getInstance()方法返回该指针,实现对单例对象的访问。

缺点:线程不安全 优点:启动快

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Singleton {
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
private:
    Singleton() {} // 将构造函数声明为私有
    static Singleton* instance; // 静态成员变量保存单例对象的指针
};
Singleton* Singleton::instance = nullptr; // 初始化单例指针为nullptr

int main() {
    Singleton* obj1 = Singleton::getInstance();
    Singleton* obj2 = Singleton::getInstance();
    // obj1和obj2指向同一个单例对象
    return 0;
}

为了解决懒汉模式中的线程安全问题,我们可以使用双重锁定(DCL, Double-Checked Locking):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <mutex>

class Singleton {
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);//std::lock_guar与mutex配合使用,把锁放到lock_guard中时,mutex自动上锁,lock_guard析构时,同时把mutex解锁
            //也可以:
            //mutex.lock();
            if (instance == nullptr) {
                instance = new Singleton();
            }
            //mutex.unlock();
        }
        return instance;
    }
private:
    Singleton() {}
    static Singleton* instance;
    static std::mutex mtx;
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;