C++之单例(singleton)模式

举报
Hermit_Rabbit 发表于 2022/10/21 22:27:30 2022/10/21
【摘要】 0. 简介有时候我们在面对通用代码时候,经常会尝试着创建多个示例函数来对一个函数多次赋值,这样会损耗很多的内存空间,这对于代码来说是不利的。而单例模式可以很好的解决这个问题。但是实现一个实用的单例模式来说,这个并不容易。 1. 单例函数 1.1 饿汉模式饿汉模式 是指单例实例在类装载时就构建,并被立即执行初始化:public class Test { private Test...

0. 简介

有时候我们在面对通用代码时候,经常会尝试着创建多个示例函数来对一个函数多次赋值,这样会损耗很多的内存空间,这对于代码来说是不利的。而单例模式可以很好的解决这个问题。但是实现一个实用的单例模式来说,这个并不容易。

1. 单例函数

1.1 饿汉模式

饿汉模式 是指单例实例在类装载时就构建,并被立即执行初始化:

public class Test {
        private Test() {
        }
        public static Test instance = new Test();// 直接对Test构造函数进行实例化
        public Test getInstance() {
                return instance;
        }
}

优点
1.线程安全
2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点
资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化 。如果类是多态的, 那静态成员变量初始化顺序还是没保证,下面我们将详细解释这个问题.

例如:有两个单例模式的类 ASingletonBSingleton, 某天你想在 BSingleton 的构造函数中使用 ASingleton 实例, 这就出问题了. 因为 BSingleton m_pInstance 静态对象可能先 ASingleton 一步调用初始化构造函数, 结果 ASingleton::getInstance() 返回的就是一个未初始化的内存区域, 程序还没跑就直接崩掉.

1.2 懒汉模式

懒汉式是指:单例实例在第一次被使用时构建,但延迟初始化:

class Test {
        private Test() {
        }
        public static Test instance = null;
        public static Test getInstance() {
                if (instance == null) {
              //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
                        instance = new Test();
                }
                return instance;
        }
}

优点:
避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。

1.3 双重模式

class Test {
        private Test() {
        }
        public static Test instance = null;

        public static Test getInstance() {
                if (instance == null) {
                        synchronized (Test.class) {
                                if (instance == null) {
                                        instance = new Test();
                                }
                        }
                }
                return instance;
        }
}

优点
资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法
缺点
第一次加载时反应不快

1.4 静态内部类

class Test {
        private Test() {
        }

        private static class SingletonHelp {
                static Test instance = new Test();
        }

        public static Test getInstance() {
                return SingletonHelp.instance;
        }
}

优点
资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
缺点
第一次加载时反应不够快

1.5 总结:

一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测 。

2 . 设计一款完美的单例模式

这里我们选择静态内部类+模板类的组合方法来有效的对多线程程序进行单例模式设计

2.1 Best Practices

网络上存在一些简单的单例模式方法,这里先对一种简单的易懂的单例模式进行解释:

#include <iostream>
#include <cassert>

class Singleton
{
public:
    static Singleton& Instance()
    {
        // https://blog.csdn.net/qq_34637408/article/details/71189382
        static Singleton instance; // 静态实例化:
        return instance;
    }
public:
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;
private:
    Singleton() = default;
    ~Singleton() = default;
};

int main()
{
    auto& a = Singleton::Instance(); //实例化
    auto& b = Singleton::Instance();
    assert(&a == &b);

    return 0;
}

…详情请参照古月居

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。