欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 单例模式

单例模式

2024/10/24 8:20:33 来源:https://blog.csdn.net/m0_59680769/article/details/141954265  浏览:    关键词:单例模式

饿汉

饿汉式(Eager Initialization)是一种简单的单例模式实现方法,在类加载时就创建唯一实例。

class Singleton {
private:// 将构造函数、拷贝构造函数和赋值运算符设为私有,防止外部实例化和复制Singleton() {}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {static Singleton instance;  // 在静态函数中创建唯一实例return instance;}
};

Singleton类中的构造函数、拷贝构造函数和赋值运算符被私有化,并且使用了delete关键字,这样可以防止外部直接实例化对象或进行拷贝。而getInstance()方法是静态方法,它返回一个指向唯一实例的引用。

在getInstance()方法中,我们使用了局部静态变量instance来保存唯一的实例。由于局部静态变量的特性,它只会在首次调用getInstance()方法时创建,之后的调用都会直接返回该实例。这样能够保证在程序启动时就创建了单例对象。

通过调用Singleton::getInstance()就可以获取到全局唯一的Singleton实例。

说明:

  • 饿汉式的特点是在类加载的时候就创建实例,所以称为"饿汉式",因为它比较"急切"地去创建实例。
  • 饿汉式的实现通过一个静态变量instance来持有唯一实例,因为静态变量在程序启动时就会初始化。
  • 由于在程序启动时就创建实例,所以不存在多线程并发访问创建实例的问题,这种方式是线程安全的。
  • 饿汉式的缺点是无法实现延迟加载,即使在某些情况下没有使用到该单例对象,它仍然会被创建和占用内存。

此外,由于静态变量的生命周期与程序的生命周期相同,如果应用程序中从未使用过该单例对象,那么它可能会浪费一些内存资源。

饿汉式是一种简单但不够灵活的单例模式实现方法。它适用于单例对象的创建成本较低的场景。

懒汉

C++中的懒汉式(Lazy Initialization)是一种延迟加载的单例模式实现方式。它只有在需要使用单例对象时才进行创建,而不是在类加载时就创建实例。

class Singleton {
private:// 私有的静态成员指针,用于存储单例对象static Singleton* instance;// 将构造函数、拷贝构造函数和赋值运算符私有化,防止外部实例化和复制Singleton() {}Singleton(const Singleton& other) {}Singleton& operator=(const Singleton& other) {}public:// 静态成员函数,用于获取单例对象的引用static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}
};// 初始化静态成员变量为nullptr
Singleton* Singleton::instance = nullptr;

Singleton类具有一个私有的静态成员指针instance,并通过调用静态成员函数getInstance()返回单例对象的引用。在首次调用getInstance()时,会检查instance是否为null,如果是,则创建一个新的Singleton对象并赋值给instance,否则直接返回现有的instance。

懒汉式单例模式延迟了对象的创建时间,当第一次使用单例对象时才进行实例化。这种延迟加载的方式可以节省资源并满足按需创建的需求。但是需要注意的是,在多线程环境下,懒汉式单例模式可能会引发线程安全问题,因为多个线程可能同时访问到getInstance()方法,从而导致创建多个实例。为了解决这个问题,可以使用线程安全的技术(如加锁)来保证只创建一个实例。

C++懒汉式(Lazy Initialization)在多线程环境下可能存在线程安全性问题。当多个线程同时调用实例获取方法时,可能会导致创建多个实例,违背了单例模式的初衷。

以下是两种常见的解决方案:

  1. 加锁:使用互斥锁(mutex)来保证在实例创建过程中只有一个线程能够进入关键代码段,其他线程需要等待。在懒汉式实例获取方法中加入互斥锁可以解决线程安全性问题。

    class Singleton {
    private:static Singleton* instance;static std::mutex mutex;Singleton() {}Singleton(const Singleton& other) {}Singleton& operator=(const Singleton& other) {}public:static Singleton* getInstance() {std::lock_guard<std::mutex> lock(mutex);  // 加锁if (instance == nullptr) {instance = new Singleton();}return instance;}
    };Singleton* Singleton::instance = nullptr;
    std::mutex Singleton::mutex;
    
  2. 双重检查锁定(Double-Checked Locking):双重检查锁定是一种优化的加锁方式,在加锁前后都进行了判断,减少了不必要的锁开销。

class Singleton {
private:static Singleton* instance;static std::mutex mutex;Singleton() {}Singleton(const Singleton& other) {}Singleton& operator=(const Singleton& other) {}public:static Singleton* getInstance() {if (instance == nullptr) {  // 第一次检查std::lock_guard<std::mutex> lock(mutex);  // 加锁if (instance == nullptr) {  // 第二次检查instance = new Singleton();  // 创建实例}}return instance;}
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

局部静态变量(Local static variable)

C++中,使用局部静态变量实现单例模式是一种常见且简洁的方式。局部静态变量指的是在函数内部定义的静态变量,这种变量在程序执行过程中只会被初始化一次。

class Singleton {
private:Singleton() {}Singleton(const Singleton& other) = delete;Singleton& operator=(const Singleton& other) = delete;public:static Singleton& getInstance() {static Singleton instance;return instance;}
};

利用了 C++11 标准的静态局部变量初始化的线程安全性质。C++11 规定对于静态局部变量的初始化是线程安全的,并且只会在第一次调用该函数时进行初始化。因此,无需额外的线程同步措施,能够确保只有一个实例被创建。

当调用 getInstance() 方法时,静态局部变量 instance 会被初始化,并返回该实例的引用。由于静态局部变量的生命周期在程序运行期间持续存在,所以每次调用 getInstance() 方法都会返回同一个实例。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com