如何实现单例模式?

embedded/2024/12/23 13:49:42/

概念

单例模式(Singleton Pattern)是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要控制资源访问的场景,如数据库连接、日志记录或者配置管理等。

方式

懒汉式单例

懒汉式单例是在第一次被请求时创建实例。为了确保线程安全,通常使用 std::mutex 进行保护。

#include <iostream>  
#include <mutex>  class Singleton {  
public:  // 禁止拷贝构造和赋值  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  static Singleton& getInstance() {  static Singleton instance; // 此时实例在第一次调用时创建  return instance;  }  void someMethod() {  std::cout << "Doing something in Singleton." << std::endl;  }  private:  Singleton() {  std::cout << "Singleton Constructor" << std::endl; // 建构函数  }  ~Singleton() {  std::cout << "Singleton Destructor" << std::endl; // 析构函数  }  
};  int main() {  Singleton::getInstance().someMethod(); // 访问单例  return 0;  
}

代码解析

  • 私有构造函数:确保外部不能直接创建实例。
  • 禁止拷贝:复制构造函数和赋值运算符被删除,以防止复制。
  • 静态局部变量:在静态方法 getInstance 中声明一个静态局部变量,这个变量 在第一次使用时初始化,后续调用将返回相同的实例。
  • 线程安全:C++11 及以上版本中,局部静态变量在多线程中是安全的,不需要额外的锁。

饿汉式单例

饿汉式单例在程序启动时就创建实例,不论是否被使用。这样可以避免多线程中的同步问题,但在资源使用上可能会浪费。

#include <iostream>  class Singleton {  
public:  // 禁止拷贝构造和赋值  Singleton(const Singleton&) = delete;  Singleton& operator=(const Singleton&) = delete;  static Singleton& getInstance() {  return instance; // 直接返回实例  }  void someMethod() {  std::cout << "Doing something in Singleton." << std::endl;  }  private:  Singleton() {  std::cout << "Singleton Constructor" << std::endl; // 建构函数  }  ~Singleton() {  std::cout << "Singleton Destructor" << std::endl; // 析构函数  }  static Singleton instance; // 静态实例  
};  // 定义静态成员  
Singleton Singleton::instance;  int main() {  Singleton::getInstance().someMethod(); // 访问单例  return 0;  
}

代码解析

  • 静态实例:在类的内部声明一个静态成员 instance,在类外定义该成员。
  • 构造函数:与懒汉式相同,构造函数和析构函数是私有的,以防止外部实例化。

线程安全的懒汉式单例(使用锁)

这种方法在创建单例实例时使用互斥锁来实现控制,确保多个线程不同时创建。

#include <iostream>  
#include <mutex>  class Singleton {  
public:  static Singleton* getInstance() {  std::lock_guard<std::mutex> lock(mu); // 加锁  if (!instance)  instance = new Singleton(); // 延迟加载  return instance;  }  void someMethod() {  std::cout << "Doing something in Singleton." << std::endl;  }  private:  Singleton() = default; // 私有构造函数  ~Singleton() = default; // 私有析构函数  Singleton(const Singleton&) = delete; // 禁止拷贝构造  Singleton& operator=(const Singleton&) = delete; // 禁止赋值  static Singleton* instance; // 静态实例指针  static std::mutex mu; // 互斥量  
};  // 定义静态成员  
Singleton* Singleton::instance = nullptr;  
std::mutex Singleton::mu;  int main() {  Singleton::getInstance()->someMethod(); // 访问单例  return 0;  
}

代码解析

  • 互斥量:使用 std::mutex 控制访问,以实现线程安全。每当访问 getInstance 时,lock_guard 自动加锁。
  • 动态分配:实例在首次访问时通过 new 创建,依赖用户在适当的位置调用 delete 销毁对象。

采用 std::call_once

C++11 中引入的 std::call_once 可以确保线程安全的单例实现。

#include <iostream>  
#include <mutex>  class Singleton {  
public:  static Singleton& getInstance() {  std::call_once(initInstanceFlag, &Singleton::initSingleton);  return *instance;  }  void someMethod() {  std::cout << "Doing something in Singleton." << std::endl;  }  private:  Singleton() {  std::cout << "Singleton Constructor" << std::endl;  }  ~Singleton() {  std::cout << "Singleton Destructor" << std::endl;  }  static void initSingleton() {  instance = new Singleton();  }  static Singleton* instance;  static std::once_flag initInstanceFlag; // 初始化标志  
};  // 静态成员初始化  
Singleton* Singleton::instance = nullptr;  
std::once_flag Singleton::initInstanceFlag;  int main() {  Singleton::getInstance().someMethod();  return 0;  
}

代码解析

  • std::once_flag:用于保证指定的函数只被调用一次。
  • std::call_once:确保在多线程环境下只会初始化一次实例。

总结

单例模式可以通过多种方式实现,包括懒汉式、饿汉式、线程安全的懒汉式、使用 std::call_once 等。选择合适的实现方式主要取决于项目的需求、线程安全需求以及如何管理生命周期等因素。对于大多数情况,使用 C++11 提供的懒汉式结合 std::call_once 是最推荐的做法,因为它既保证了线程安全,又简洁易懂。


http://www.ppmy.cn/embedded/148078.html

相关文章

工厂常用软件系统大全中英文全称对照表及功能介绍应用场景ERP MES WMS SCADA IOT SAP等软件系统介绍

1. ERP&#xff08;Enterprise Resource Planning&#xff09;企业资源计划&#xff1a; ○ 功能&#xff1a;整合企业的各项资源和业务流程&#xff0c;涵盖从采购、生产到销售的各个环节。包括财务管理、生产计划、采购管理、库存管理、销售管理、人力资源管理等。 ○ 应用场…

使用Laravel构建你的第一个Web应用

使用Laravel构建你的第一个Web应用 Laravel是一个现代化的PHP框架&#xff0c;以其优雅的语法和强大的功能而闻名。它提供了许多内置工具和功能&#xff0c;使得开发Web应用变得更加高效和便捷。本文将指导你如何使用Laravel构建你的第一个Web应用&#xff0c;涵盖环境设置、项…

2024年12月22日Github流行趋势

项目名称&#xff1a;donnemartin / system-design-primer 项目维护者&#xff1a;donnemartin, cclauss, satob, fluency03, linhe0x0 等项目介绍&#xff1a;学习如何设计大规模系统。为系统设计面试做准备。包括Anki闪卡。项目star数&#xff1a;280,653项目fork数&#xff…

深入理解Kafka:核心设计与实践原理读书笔记

目录 初识Kafka基本概念安装与配置ZooKeeper安装与配置Kafka的安装与配置 生产与消费服务端参数配置 生产者客户端开发消息对象 ProducerRecord必要的参数配置发送消息序列化分区器生产者拦截器 原理分析整体架构元数据的更新 重要的生产者参数acksmax.request.sizeretries和re…

Vue.js前端框架教程3:Vue setup语法糖和异步操作

文章目录 script setup基本语法使用 Composition API组件定义使用生命周期钩子模板引用使用 `defineProps` 和 `defineEmits`组合多个 `<script setup>` 标签Vue异步操作1. 使用 `async` 和 `await`2. 使用 Promise3. 在 `created` 或 `mounted` 钩子中执行异步操作4. 使…

题海拾贝:21.合并两个有序链表

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

WatchAlert - 开源多数据源告警引擎

概述 在现代 IT 环境中&#xff0c;监控和告警是确保系统稳定性和可靠性的关键环节。然而&#xff0c;随着业务规模的扩大和数据源的多样化&#xff0c;传统的单一数据源告警系统已经无法满足复杂的需求。为了解决这一问题&#xff0c;我开发了一个开源的多数据源告警引擎——…

CSS 第七章

B站《前端Web开发HTML5CSS3移动web视频教程》第九天和第10天的课程&#xff1a;SEO、Favicon、小兔鲜网页制作。 一、项目目录 1.根文件夹xtx-pc 2.子文件夹 images文件夹&#xff1a;存放固定使用的图片素材uploads文件夹&#xff1a;存放非固定使用的图片素材iconfont文件…