c++单例模式-6种单例层层迭代优化

简介: 6种单例模式,层层迭代优化

定义
单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
他应该满足以下几点:

1:确保一个类只有一个实例被建立     

2:构造函数应该声明为非公有,从而禁止外界创建实例。
3:拷贝操作和移动操作也应该禁止。
4:提供公有方法获取实例
5:支持多线程

版本1(懒汉)
缺点:
1:没有对资源进行释放
2:不支持多线程

    class Singleton {
   
    public:
    static Singleton * GetInstance() {
   
        if (_instance == nullptr) {
   
            _instance = new Singleton();
        }
        return _instance;
        }
        private:
        Singleton(){
   }//构造
        Singleton(const Singleton &clone){
   } //拷⻉构造
        Singleton& operator=(const Singleton&) {
   }
        stati    c Singleton * _instance;
    }
    Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

版本2
缺点:
1:不支持多线程

    class Singleton {
   
    public:
    static Singleton * GetInstance() {
   
        if (_instance == nullptr) {
   
            _instance = new Singleton();
            atexit(Destructor);
        }
        return _instance;
        }
        ~Singleton() {
   }
        private:
        static void Destructor() {
   
            if (nullptr != _instance) {
   
            delete _instance;
            _instance = nullptr;
        }
        }
        Singleton();//构造
        Singleton(const Singleton &cpy); //拷⻉构造
        Singleton& operator=(const Singleton&) {
   }
        static Singleton * _instance;
    }
    Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

版本3(双重校验锁)
此代码是否感觉很安全,但实际上有重大问题
首先new一个对象时,分为三个步骤,1分配内存 2构造对象 3返回指针。所以常规顺序是123,但是编译器有时候为了优化会指令重排,导致顺序变成132,这里我们考虑这么一种情况
A线程:new1分配内存并按照指令重拍之后的顺序将2地址返回_instance 指针(这时候_instance 指针是非空的,但是还没有到达构造构造,此时时间片用完,线程切换)
B线程进入,此时发现_instance 是非空的,便直接将_instance返回给调用者,而调用着使用这个没有构造的对象将会发生不可预测的后果

指令重拍原因很多,比如编译器优化或者cpu指令流水线导致,具体可以查阅相关资料

    /****************************************
    static Singleton * GetInstance();
    加锁位置:由于除了第一次是需要new,后面调用都只是获取实例,所以在3.1处加锁会极大的损耗性能,故在3.2处通过if判断后才加锁,
    两次if判空原因:主要是考虑多线程环境线程切换因素
    *****************************************/
    #include <mutex>
    class Singleton {
    // 懒汉模式 lazy load
    public:
    static Singleton * GetInstance() {
   
        //std::lock_guard<std::mutex> lock(_mutex); // 3.1 切换线程
        if (_instance == nullptr) {
   
            std::lock_guard<std::mutex> lock(_mutex); // 3.2
            if (_instance == nullptr) {
   
            _instance = new Singleton();
            atexit(Destructor);
            }
        }
        return _instance;
    }
    private:
        static void Destructor() {
   
            if (nullptr != _instance) {
   
                delete _instance;
                _instance = nullptr;
            }
        }
        Singleton(){
   } //构造
        Singleton(const Singleton &cpy){
   } //拷⻉构造
        Singleton& operator=(const Singleton&) {
   }
        static Singleton * _instance;
        static std::mutex _mutex;
    }
    Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
    std::mutex Singleton::_mutex; //互斥锁初始化

版本4
解决版本三问题,但是代码显得很臃肿

    #include <mutex>
    #include <atomic>
    class Singleton {
   
    public:
        static Singleton * GetInstance() {
   
            Singleton* tmp = _instance.load(std::memory_order_relaxed);//加载实例
            std::atomic_thread_fence(std::memory_order_acquire);//获取内存屏障
            if (tmp == nullptr) {
   
                std::lock_guard<std::mutex> lock(_mutex);
                tmp = _instance.load(std::memory_order_relaxed);
                if (tmp == nullptr) {
   
                    tmp = new Singleton;
                    std::atomic_thread_fence(std::memory_order_release);//释放内存屏障
                    _instance.store(tmp, std::memory_order_relaxed);
                    atexit(Destructor);
                }
            }
            return tmp;
        }
    private:
        static void Destructor() {
   
        Singleton* tmp = _instance.load(std::memory_order_relaxed);
        if (nullptr != tmp) {
   
            delete tmp;
        }
    }
        Singleton(){
   }
        Singleton(const Singleton&) {
   }
        Singleton& operator=(const Singleton&) {
   }
        static std::atomic<Singleton*> _instance;
        static std::mutex _mutex;
    };
    std::atomic<Singleton*> Singleton::_instance;//静态成员需要初始化
    std::mutex Singleton::_mutex; //互斥锁初始化

版本5
c++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发线程将会阻塞等待初始化结束。
缺点:无法继承

    class Singleton
    {
   
    public:
        ~Singleton(){
   }
        static Singleton& GetInstance() {
   
            static Singleton instance;
            return instance;
    }
    private:
        Singleton(){
   }
        Singleton(const Singleton&) {
   }
        Singleton& operator=(const Singleton&) {
   }
    };

版本6

    template<typename T>
    class Singleton {
   
    public:
        static T& GetInstance() {
   
            static T instance; // 这⾥要初始化DesignPattern,需要调⽤DesignPattern 构造函数,同时会调⽤⽗类的构造函数。
            return instance;
        }
    protected:
        virtual ~Singleton() {
   }
        Singleton() {
   } // protected修饰构造函数,才能让别⼈继承
        Singleton(const Singleton&) {
   }
        Singleton& operator =(const Singleton&) {
   }
    };
    class DesignPattern : public Singleton<DesignPattern> {
   
        friend class Singleton<DesignPattern>; // friend 能让 Singleton<T> 访问到 DesignPattern构造函数
    private:
        DesignPattern(){
   }
        DesignPattern(const DesignPattern&) {
   }
        DesignPattern& operator=(const DesignPattern&) {
   }
    }
目录
相关文章
|
2月前
|
存储 缓存 算法
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能
120 0
|
2月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
62 0
|
2月前
|
存储 算法 编译器
C/C++编译器局部优化技术:局部优化是针对单个函数或基本块进行的优化
C/C++编译器局部优化技术:局部优化是针对单个函数或基本块进行的优化
36 0
|
2月前
|
存储 缓存 算法
高效编程:我们应该了解哪些编译器优化技术?如何做出成熟的优化行为,掌握C++编程中的编译器优化艺术。
高效编程:我们应该了解哪些编译器优化技术?如何做出成熟的优化行为,掌握C++编程中的编译器优化艺术。
92 4
|
1天前
|
消息中间件 算法 Java
C++实时通信优化技术探究
C++实时通信优化技术探究
10 3
|
7天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计
|
7天前
|
设计模式 安全 编译器
【代码片段】【C++】C++11线程安全单例模式
【代码片段】【C++】C++11线程安全单例模式
13 1
|
2月前
|
编译器 C++
【C++练级之路】【Lv.4】类和对象(下)(初始化列表,友元,static成员,编译器的优化)
【C++练级之路】【Lv.4】类和对象(下)(初始化列表,友元,static成员,编译器的优化)
|
2月前
|
存储 算法 数据管理
C++中利用随机策略优化二叉树操作效率的实现方法
C++中利用随机策略优化二叉树操作效率的实现方法
77 1
|
2月前
|
算法 测试技术 数据处理
【C++ 设计思路】优化C++项目:高效解耦库接口的实战指南
【C++ 设计思路】优化C++项目:高效解耦库接口的实战指南
75 5