码迷,mamicode.com
首页 > 编程语言 > 详细

c++设计模式-单例模式

时间:2020-01-27 00:13:32      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:独立   构造   结束   c++   限制   语句   tran   设计   oschina   

定义
只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例
具体运用场景
1.设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;
2.数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;
要点
1.全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private)
2.禁止赋值和拷贝
3.用户通过接口获取实例:使用 static 类成员函数
4.线程安全
实现
示例一、没有考虑线程安全的方式

class Singleton{
private:
    Singleton(){
        //......
    }
    Singleton(Singleton&);
    Singleton& operator=(const Singleton&);
    static Singleton* instance_ptr;
public:
    ~Singleton(){
        //.....
    }
    static Singleton* get_instance(){
        if(instance_ptr==nullptr){
              instance_ptr = new Singleton;
        }
        return instance_ptr;
    }
};

Singleton* Singleton::instance_ptr = nullptr;

int main(){
    Singleton* instance = Singleton::get_instance();
    return 0;
}

线程安全:上述中,可能会造成多个线程对共享内存数据访问的竞争条件的形成:即,第一个线程在访问if语句时判断instance_ptr为空,开始实例化单例。同时,第二个线程访问单例,判断到if还是为空,也开始实例化单例。

C++标准中对数据竞争的定义是:多个线程并发的去修改一个独立对象,数据竞争是未定义行为的起因。

内存泄漏:这个类没有负责delete对象,需要使用者自己delete,因此存在内存泄漏的风险。
示例二、线程安全的方式

//include<mutex>
class Singleton{
private:
    Singleton(){
        //......
    }
    Singleton(Singleton&);
    Singleton& operator=(const Singleton&);
    static Singleton* instance_ptr;
    static std::mutex m_mutex;
public:
    ~Singleton(){
        //.....
    }
    static Singleton* get_instance(){
        if(instance_ptr==nullptr){
            std::lock_guard<std::mutex> lk(m_mutex);
            if(instance_ptr==nullptr) {
                instance_ptr = new Singleton;
            }
        }
        return instance_ptr;
    }
};
// init static member
Singleton* Singleton::instance_ptr = nullptr;

int main(){
    Singleton* instance = Singleton::get_instance();
    return 0;
}

加锁,这里使用了两个 if判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,避免每次调用 get_instance都加锁。

互斥:是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

看起来很美好,但这样是有问题的,在某些平台,双重检查锁定模式会失效!具体可以看这篇文章
示例三、c++11中的静态局部变量的线程安全

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

这种方法叫做 Meyers‘ Singleton ,是Meyers提出的。所用到的特性是在C++11标准中的Magic Static特性:
如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。

c++设计模式-单例模式

标签:独立   构造   结束   c++   限制   语句   tran   设计   oschina   

原文地址:https://www.cnblogs.com/Redwarx008/p/12235125.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!