C++设计模式-单例模式 原创 设计模式 2021年10月12日 07:15 夏至未至 1397 当前内容 5047 字,在路上,马上到,马上到 ### 目录 [TOC] ### 什么是单例类 一个类,该类会实例化自己的对象,同时呢,又保证只有这一个对象被实例化即被创建。之后,该类会提供一个方法,用来访问该类唯一被创建的对象,此方法可以直接访问(静态方法)。这个类称为单例类,单例模式是一种对象创建型模式。 ### 为什么要用这样的单例类 一个类,如果被全局使用,然后重复的、频繁的创建和销毁,比如一些管理类,这个类就应该被设计为单例类。 ### 如何创建单例类 1. 构造函数私有化,避免类外再实例化。 2. 静态方法,返回该类唯一实例化的对象。(方法内需要判断系统是否已经有这个单例,如果有则返回,如果没有则创建) ### 何时使用单例类 系统只需要一个实例对象,比如,数据库管理类,只允许创建一个对象。 类实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。 ### 单例特点 #### 优点 在内存里只有一个实例,减少了内存的开销,特别是频繁的创建和销毁实例。 避免了对资源的多重使用,比如项目的配置文件,单次只能有一个人在修改。 #### 缺点 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。 ### 代码实现 #### 饿汉式单例 只在第一次用到类实例的时候才实例化。 > 不支持延迟加载,初始化即实例化 由于是一个static对象,可以保证对象只生成一次,是线程安全的。 以下代码可以直接上线运行: ##### 源码 #include // 饿汉式单例类 class HungrySingleton { public: // 访问唯一实例对象的方法 static HungrySingleton* getInstance() { return instance; } // 销毁唯一实例对象 static void delInstance() { if (instance != nullptr) { delete instance; instance = nullptr; } } private: HungrySingleton() { std::cout << "饿汉对象创建" << std::endl; }; ~HungrySingleton() { std::cout << "饿汉对象销毁" << std::endl; } // static 可以保证对象只生成一次,且线程安全 static HungrySingleton* instance; }; // 初始化即实例化(这也是饿的体现,着急实例化) HungrySingleton* HungrySingleton::instance = new HungrySingleton(); // 测试饿汉单例 int main() { // 模拟频繁创建 HungrySingleton* hungry1 = HungrySingleton::getInstance(); HungrySingleton* hungry2 = HungrySingleton::getInstance(); // 通过对象地址判断获取到得是不是唯一对象 std::cout << "hungry1 address = " << hungry1 << std::endl; std::cout << "hungry2 address = " << hungry2 << std::endl; // 销毁唯一对象 HungrySingleton::delInstance(); getchar(); return 0; } ##### 输出 饿汉对象创建 hungry1 address = 01181DB8 hungry2 address = 01181DB8 饿汉对象销毁 #### 懒汉式 懒汉式单例在第一次调用getInstance()方法时实例化。 > 类加载时并不自行实例化,这种技术又称为**延迟加载*(Lazy Load)***技术,即需要的时候再加载实例 为了避免多个线程同时调用getInstance()方法,我们可以使用锁或者static变量 ##### 懒汉式单例类+双检查+锁 ###### 源码 #include #include class LazySingleton { public: // 单例提供访问唯一实例方法 static LazySingleton* getInstance() { // 锁不是一进来就加,当 instance 不为空,那这个方法就是只读对象,没必要加锁 if (instance == nullptr) { // 只有为空的时候,new 对象,需要加锁 std::lock_guard lck(m_mutex); if (instance == nullptr) { instance = new LazySingleton; } } return instance; } // 销毁唯一对象 static void delInstance() { if (instance != nullptr) { delete instance; instance = nullptr; } } private: // 构造私有,即只能内部实例化 LazySingleton() { std::cout << "懒汉构造" << std::endl; }; // 析构私有,即只能内部销毁,外部不可 delete ~LazySingleton() { std::cout << "懒汉销毁" << std::endl; } static std::mutex m_mutex; static LazySingleton* instance; }; std::mutex LazySingleton::m_mutex; LazySingleton* LazySingleton::instance = nullptr; int main() { // 模拟频繁创建 LazySingleton* lazy1 = LazySingleton::getInstance(); LazySingleton* lazy2 = LazySingleton::getInstance(); std::cout << "lazy1 address = " << lazy1 << std::endl; std::cout << "lazy2 address = " << lazy2 << std::endl; // 销毁 LazySingleton::delInstance(); getchar(); return 0; } ###### 输出 懒汉构造 lazy1 address = 0072E260 lazy2 address = 0072E260 懒汉销毁 ##### 懒汉式单例类+static变量 ###### 源码 #include class LazySingleton { public: // 返回静态变量,类内唯一 static LazySingleton* getInstance() { static LazySingleton instance; return &instance; } private: LazySingleton() { std::cout << "懒汉构造" << std::endl; }; ~LazySingleton() { std::cout << "懒汉析构" << std::endl; } }; int main() { // 模拟频繁创建 LazySingleton* lazy1 = LazySingleton::getInstance(); LazySingleton* lazy2 = LazySingleton::getInstance(); std::cout << "lazy1 address = " << lazy1 << std::endl; std::cout << "lazy2 address = " << lazy2 << std::endl; getchar(); return 0; } ###### 输出 懒汉构造 lazy1 address = 00F9D140 lazy2 address = 00F9D140 ###### 关于使用 static 1.C++11中可以保证static变量时多线程安全的,在底层实现了加锁操作,所以不需要像以前那样自己写加锁操作。 2.由于是一个static对象,可以保证对象只生成一次; 3.在程序结束的时候,系统会调用对应的析构函数;如果是new出来的对象,程序结束的时候,系统不会自动调用析构函数,而是需要手动释放。 本文标题: C++设计模式-单例模式 本文作者: 夏至未至 发布时间: 2021年10月12日 07:15 最近更新: 2022年7月4日 16:34 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 设计模式(25) 单例模式(1) 上一个 C++设计模式-简单工厂模式 下一个 设计模式概述 请可爱的你登录后回复 评论列表 (0条) 查看更多评论
评论列表 (0条)