C++ 【单例模式】

这篇具有很好参考价值的文章主要介绍了C++ 【单例模式】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简单介绍

单例模式是一种创建型设计模式 | 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
它也会破坏代码的模块化特性,因为单例模式往往会承担了很多的职责,导致与 其他模块 产生过多的耦合

基础理解

单一职责原则:

  • 一个类或模块应该只有一个引起它变化的原因。(确保了只有一个实例)
  • 一个类或模块应该只负责一种功能或行为。(同上)
  • 将不同的功能分离开来,避免将不相关的功能耦合在一起。
    • (单例模式不满足,它同时会有许多职责)

单例模式同时解决了两个问题, 也违反了单一职责原则:

  1. 保证一个类只有一个实例:在需要控制共享资源权限的情况下就十分有用。你创建的所有实例对象都是 获得 第一次创建的实例对象,而不是一个新对象
  2. 为该实例提供一个全局访问节点:和全局变量一样,允许在程序的任何地方访问。 但是它可以保护该实例不被其他代码覆盖。(因为设置了私有)

UML 图

单例 (Singleton) 类声明了一个名为 get­Instance 获取实例的静态方法来返回其所属类的一个相同实例。客户端只允许调用该方法获得实例
单例的构造函数必须对客户端 (Client) 代码隐藏(私有化) 。 调用 获取实例方法必须是获取单例对象的唯一方式。
C++ 【单例模式】,23个设计模式,c++,单例模式,开发语言,设计模式

实现方式

  1. 在类中添加一个私有静态成员变量用于保存单例实例。
  2. 声明一个公有静态构建方法用于获取单例实例。
  3. 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。
  4. 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。

c++ 11 中使用基本的饿汉单例模式是十分简单的, 将GetInstance 设置为static即可,但此单例模式在多线程中会出错,所以需要执行加锁操作.

#include <iostream>  // std::cout
#include <mutex>     // std::mutex
#include <pthread.h> // pthread_create

///  加锁的懒汉式实现  //

class SingleInstance
{

public:
    // 获取单实例对象
    static SingleInstance *&GetInstance(); // 重点

    // 释放单实例,进程退出时调用
    static void deleteInstance();

    // 打印实例地址
    void Print();

private:
    // 将其构造和析构成为私有的, 禁止外部构造和析构
    SingleInstance();
    ~SingleInstance();

    // 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值
    SingleInstance(const SingleInstance &signal);
    const SingleInstance &operator=(const SingleInstance &signal);

private:
    // 唯一单实例对象指针
    static SingleInstance *m_SingleInstance;
    static std::mutex m_Mutex;
};

// 初始化静态成员变量
SingleInstance *SingleInstance::m_SingleInstance = NULL;
std::mutex SingleInstance::m_Mutex;

SingleInstance *&SingleInstance::GetInstance()
{

    //  这里使用了两个 if判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,
    //  避免每次调用 GetInstance的方法都加锁,锁的开销毕竟还是有点大的。
    if (m_SingleInstance == NULL)
    {
        std::unique_lock<std::mutex> lock(m_Mutex); // 加锁
        if (m_SingleInstance == NULL)
        {
            m_SingleInstance = new (std::nothrow) SingleInstance; // 第一次为空时创建 以后直接返回第一次创建的实例
        }
    }

    return m_SingleInstance;
}

void SingleInstance::deleteInstance()
{
    std::unique_lock<std::mutex> lock(m_Mutex); // 加锁
    if (m_SingleInstance)
    {
        delete m_SingleInstance;
        m_SingleInstance = NULL;
    }
}

void SingleInstance::Print()
{
    std::cout << "我的实例内存地址是:" << this << std::endl;
}

SingleInstance::SingleInstance()
{
    std::cout << "构造函数" << std::endl;
}

SingleInstance::~SingleInstance()
{
    std::cout << "析构函数" << std::endl;
}
///  加锁的懒汉式实现  //

void *PrintHello(void *threadid)
{
    // 主线程与子线程分离,两者相互不干涉,子线程结束同时子线程的资源自动回收
    pthread_detach(pthread_self());

    // 对传入的参数进行强制类型转换,由无类型指针变为整形数指针,然后再读取
    int tid = *((int *)threadid);

    std::cout << "Hi, 我是线程 ID:[" << tid << "]" << std::endl;

    // 打印实例地址
    SingleInstance::GetInstance()->Print();

    pthread_exit(NULL);
    return NULL;
}

#define NUM_THREADS 5 // 线程个数

int main()
{
    pthread_t threads[NUM_THREADS] = {0};
    int indexes[NUM_THREADS] = {0}; // 用数组来保存i的值

    int ret = 0;
    int i = 0;

    std::cout << "main() : 开始 ... " << std::endl;

    for (i = 0; i < NUM_THREADS; i++)
    {
        std::cout << "main() : 创建线程:[" << i << "]" << std::endl;

        indexes[i] = i; // 先保存i的值

        // 传入的时候必须强制转换为void* 类型,即无类型指针
        ret = pthread_create(&threads[i], NULL, PrintHello, (void *)&(indexes[i]));
        if (ret)
        {
            std::cout << "Error:无法创建线程," << ret << std::endl;
            exit(-1);
        }
    }

    // 手动释放单实例的资源
    SingleInstance::deleteInstance();
    std::cout << "main() : 结束! " << std::endl;

    system("pause");
}

应用场景

使用场景就是它的两个特性:

  1. 如果某个类对于所有客户端只有一个可用的实例

单例模式返回的永远只有第一个创建的实例对象,

  1. 更加严格地控制全局变量

除了单例类自己以外, 无法通过任何方式替换的第一个创建的实例。可以修改getInstance 调整单例实例的数量

与其他模式的关系

  1. 外观模式类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。

  2. 抽象工厂模式、 生成器模式和原型模式都可以用单例来实现。

  3. 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式就和单例类似了。 但这两个模式有两个根本性的不同。

    • 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
    • 单例对象可以是可变的。 享元对象是不可变的。

优缺点

优点 缺点
你可以保证一个类只有一个实例。 违反了单一职责原则。 该模式同时解决了两个问题。
你获得了一个指向该实例的全局访问节点。 单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等
仅在首次请求单例对象时对其进行初始化。 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
单例的客户端代码单元测试可能会比较困难, 因为许多测试框架以基于继承的方式创建模拟对象。 由于单例类的构造函数是私有的, 而且绝大部分语言无法重写静态方法, 所以你需要想出仔细考虑模拟单例的方法。 要么干脆不编写测试代码, 或者不使用单例模式。

单例模式被视为一种反模式。 因此它在 C++ 代码中的使用频率正在减少。不过还是有用的.使用好它只需要记住它的两个特点即可

如果有错还望指正。有什么建议也可以留言。
参考文章文章来源地址https://www.toymoban.com/news/detail-848416.html

到了这里,关于C++ 【单例模式】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java中23种设计模式-单例模式--饿汉式】

    加油,新时代打工人! 简单粗暴,直接上代码。 23种设计模式定义介绍 Java中23种设计模式-单例模式 Java中23种设计模式-单例模式2–懒汉式线程不安全 Java中23种设计模式-单例模式2–懒汉式2线程安全

    2024年02月22日
    浏览(49)
  • Java23种设计模式-创建型模式之单例模式

    单例模式 (Singleton Pattern):通过单例模式的方法创建的 类在当前进程中只有一个实例 (根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例),该类负责 创建自己的对象 ,同时 确保只有单个对象 被创建。 注 : 1、单例类 只能 有 一个实例 。

    2024年04月26日
    浏览(54)
  • 用Rust实现23种设计模式之单例

    话不多说,上代码! 在这个例子中,我们使用了 Arc (原子引用计数)和 Mutex (互斥锁)来实现线程安全的单例。通过 get_instance 方法,我们可以获取到单例实例,并对实例进行操作。 使用 lazy_static crate: lazy_static crate 是一个常用的 Rust crate,可以实现懒加载的全局静态变量

    2024年02月14日
    浏览(42)
  • 从C语言到C++_37(特殊类设计和C++类型转换)单例模式

    目录 1. 特殊类设计 1.1 不能被拷贝的类 1.2 只能在堆上创建的类 1.3 只能在栈上创建的类 1.4 不能被继承的类 1.5 只能创建一个对象的类(单例模式)(重点) 1.5.1 饿汉模式 1.5.2 懒汉模式 2. 类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3. RTTI(了解)和类型转换常见面

    2024年02月10日
    浏览(50)
  • 【设计模式】23种设计模式——单例模式(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    介绍 所谓类的单例设计模式,就是采取一定的方法, 保证在整个的软件系统中,对某个类只能存在一个对象实例 ,并且该类只提供一个取得其对象实例的方法(静态方法)。 比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建Session对象。SessionFactory并不是轻量

    2024年02月13日
    浏览(45)
  • 【Java中23种设计模式-单例模式2--懒汉式2线程安全】

    加油,新时代打工人! 简单粗暴,学习Java设计模式。 23种设计模式定义介绍 Java中23种设计模式-单例模式 Java中23种设计模式-单例模式2–懒汉式线程不安全 通过运行结果看,两个线程的地址值是相同的,说明内存空间里,创建了一个对象。

    2024年02月20日
    浏览(46)
  • 【C++】设计模式-单例模式

    目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式  二、懒汉模式实现 1.基本实现 2.锁+静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定+智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄漏

    2024年02月16日
    浏览(38)
  • C++设计模式:单例模式(十)

    1、单例设计模式 单例设计模式,使用的频率比较高,整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式,同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉式:类加载的准备阶段

    2024年04月14日
    浏览(47)
  • 【设计模式】C++单例模式详解

    ⼀个类仅有⼀个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 那么,我们必须保证: 该类不能被复制;也不能被公开的创造。 对于 C++ 来说,它的构造函数,拷贝构造函数和赋值函数都不能被公开调用。 单例模式又分为 懒汉模式 和 饿汉模式 ,它们

    2024年02月05日
    浏览(48)
  • C++设计模式代码--单例模式

    参考:5. 单例模式(Singleton) (yuque.com) 1、什么是单例模式 保证一个类只有一个实例,并提供一个访问该实例的全局节点; 2、什么情况下需要单例模式 某个类的对象在软件运行之初就创建,并且在软件的很多地方都需要读写这个类的信息;使用单例模式的话,类对象就只要

    2024年02月03日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包