C++设计模式一 、单例模式。

C++实现单例模式

解释:顾名思义,单例模式就是只有一个实例。在有些设计过程中,我们只希望生成一个模式,比如网页中的对话框、聊天界面(每个联系人只能打开一个聊天界面),内存池等,如果出现多个实例,则会造成严重的后果。

一、简单实现:

class Singleton
{
public:
    static Singleton*getinstance();
    ~Singleton();
private:
    Singleton();//私有构造函数
    Singleton(const Singleton &);//复制构造函数
    static Singleton *instance;       
}
Singleton::Singleton(){}
Singleton::Singleton(const Singleton&){}
Singleton*Singleton::getinstance()
{
    if(instance == NULL)
    {
        instance = new Singleton;
    }
    return instance;
}
Singleton::~Singleton(){}


有几点需要注意:

1)一般的构造函数都是public的,但是此处的构造函数声明为了私有,这里理解应该为是单例模式的核心所在,将构造函数声明为私有,则外在的程序就不能使用new来实例化,这就是让类自身负责保存他唯一的实例,这个类可以保障没有其他实例可以被创建。

2)由于外部的代码不能实例化,我们写了一个public的函数getinstance,该函数的目的就是返回一个实例。

3)此为懒汉模式,懒汉模式是加载时没有创建实例,在获取对象的时候创建,因此加载速度快,但是获取对象慢。懒汉模式有个致命问题,在多线程的时候不安全,因为若有多个线程同时运行到此处,则会创建多个实例,这也就失去了单例模式的意义。可以通过加锁来解决此问题。

二、多线程安全的单例模式

实现1:懒汉加锁模式

class Singleton
{
protected:
    Singleton()
    {
        pthread_mutex_init(&mutex);    
    }
private:
    Singleton();//私有构造函数
    Singleton(const Singleton &);//复制构造函数
    static Singleton*p;
public:
    static pthread_mutex_t mutex;
    static Singleton*instance;
}
pthread_mutex_t singleton::mutex;
Singleton::Singleton(){}
Singleton::Singleton(const Singleton &){}
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
    if (p == NULL)
    {
        pthread_mutex_lock(&mutex);
        if (p == NULL)
            p = new singleton();
        pthread_mutex_unlock(&mutex);
    }
    return p;
}

注意:

1)加锁是确保一个线程进入临界区,另一个线程进不去。当一个线程进入锁定的代码,另一个就会一直等待,直到线程被释放。

2)此处有两个判断,被称为双重锁定。因为若有两个线程同时执行到这里的时候,他们都会通过第一层判断,但是由于加锁的原因,第一个进去创建了实例并且出来之后,第二个才被允许进入,若不进行第二项为空的判断,则第二个线程又会创建一个实例,则单例模式失效。

实现2:懒汉静态变量模式。

class Singleton
{
private:
    Singleton();
public:
    static Singleton *instance();
    static pthread_mutex_t mutex;
}
pthread_mutex_t Singleton::mutex;//此处一定要定义,由于是静态变量,必须要在外部定义和初始化
Singleton::Singleton()
{
    pthread_mutex_init(&mutex);
}
Singleton *Singleton::instance()
{
    pthread_mutex_lock(&mutex);
    static Singleton obj;
    pthread_mutex_unlock(&mutex);
    return &obj;
}

这里简单介绍一下静态变量:

         当我们每创建一个类对象,类成员变量就会多出一份,各个对象间的成员变量不能共享,是各自独立的变量。但是,我们有些时候需要定义一个成员变量,使其在各个类对象之间关联起来。也就是说这个变量是所有的类共有,这就是静态变量。静态变量的特性和全局变量特性相同,生命周期为程序运行期,不依赖于任何实例的对象。

引申静态成员函数:

静态成员函数属于整个类所有,因为静态成员函数并不属于某个对象,所以我们可以通过类名来直接访问公有静态成员函数。也可以通过对象名访问公有成员函数。由于构造函数为私有,所以不可以通过外部函数来获取实例,只能通过静态函数来获取单例。

所以上面函数,当有多个实例调用instance的时候,返回的都是同一个实例obj。

三、 多线程安全的饿汉模式

代码实现:

class Singleton
{
private:
    Singleton();
    Singleton(const Singleton&);
    static Singleton * p;
public:
    Singleton * instance();
}
Singleton::Singleton(){}
Singleton::Singleton(const Singleton&){}//复制构造函数
Singleton *Singleton::p=new Singleton;
Singleton *Singleton::instance()
{
    return p;
}

注意:

1)饿汉模式,顾名思义,需要提前喂食,也即是提前加载。采用静态初始化的方式,提前加载实例化对象,但是由于提前加载,也就提前占用了系统资源,导致内存开销大。

2)此处没有加锁为什么也是线程安全的?因为程序在刚加载的时候就创建了实例,并且返回他,以后如果再次运行到这里,返回的就是之前加载时创建的实例,所以不会导致多线程安全问题。

3)类指针要声明为静态的,否则不可以在类外进行赋值操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值