C++设计模式——单例模式

C++设计模式——单例模式

概述

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例

单例模式的实现大概可以分为懒汉式实现和饿汉式实现。顾名思义,懒汉式就说明它很懒,只有在使用的时候才去创建对象。而饿汉式说明它很饿,还没开始使用就迫不及待的将对象创建出来了。

饿汉式实现

//Singleton.h
#ifndef SIGLETON_H_
#define SIGLETON_H_

class Singleton
{
public:
  static Singleton* GetInstance(); //公有的获取对象的接口
private:
  Singleton(){} //私有的构造函数

  static Singleton* m_instance;
};
#endif
//Singleton.cpp
#include "Singleton.h"

Singleton* Singleton::m_instance = new Singleton();

Singleton* Singleton::GetInstance()
{
  return m_instance;
}

饿汉式实现的优缺点

优点

  • 无须担心多线程的问题。

  • 不需要加锁,执行效率比较高

缺点

  • 在类刚加载的时候,就创建了该单例,消耗内存。

懒汉式实现

//Singleton.h
#ifndef SIGLETON_H_
#define SIGLETON_H_

class Singleton
{
public:
  static Singleton* GetInstance();//公有的获取对象的接口
private:
  Singleton(){} //私有的构造函数

  static Singleton* m_instance;
};
#endif
//Singleton.cpp
#include "Singleton.h"

Singleton* Singleton::m_instance = NULL;

Singleton* Singleton::GetInstance()
{
  if (NULL == m_instance)
  {
    m_instance = new Singleton();
  }
  return m_instance;
}

懒汉式实现优缺点

优点
- 不会在类刚加载的时候就初始化,能节省内存消耗

缺点
- 多线程不安全,必须要通过加锁来保证多线程安全,这样对运行效率有点影响。

懒汉式实现优化

使用加锁来实现懒汉式单例模式.

//Singleton.h
#ifndef SIGLETON_H_
#define SIGLETON_H_
#include <iostream>
#include <mutex> //C++11

class Singleton
{
public:
  static Singleton* GetInstance();

private:
  Singleton(){} //私有的构造函数

  static Singleton* m_instance;
  static mutex m_mutex;  //锁
};
#endif
//Singleton.cpp

#include "Singleton.h"

Singleton* Singleton::m_instance = NULL;
mutex Singleton::m_mutex;

Singleton* Singleton::GetInstance()
{
  if (NULL == m_instance)
  {
    std::lock_guard<std::mutex> lock(m_mutex); //在这儿上锁判断,只有多线程访问的时候才会执行上锁解锁,有效的缓解了加锁引起的效率问题。
    if (NULL == m_instance)
    {
      m_instance = new Singleton();      
    }
  }
  return m_instance;
}

内存释放问题

    说了这么多,关于懒汉式单例模式创建之后的释放问题一直没有解决,我们在第一次初始化的时候创建出来,什么时候去释放它呢?提到这儿,懒汉式单例模式针对资源释放又衍生出了另外的四种实现方式。

1.局部静态变量返回引用实现

#ifndef SIGLETON_H_
#define SIGLETON_H_
#include <iostream>

class Singleton
{
public:
  static Singleton& GetInstance()
  {
    static Singleton instance; //为了说明问题,忽略多线程。实际实现加锁和前面的懒汉式实现相同。
    return instance;
  }
private:
  Singleton(){} //私有的构造函数
};

如此一来,对于单例的释放问题就很简单的解决了,但是如果代码中出现这样使用单例的:

Singleton instance = Singleton::GetInstance();

由于编译器在编译的时候,会自动生成拷贝构造函数,如果这样使用,会调用类的拷贝构造函数,从而制造出另外一个单例对象,这对于单例模式的初衷是矛盾的。因此,针对该问题,有了两种解决办法。

第一种解决办法,也就是懒汉式单例模式实现的第二种方法

2.局部静态变量返回指针实现

#ifndef SIGLETON_H_
#define SIGLETON_H_
#include <iostream>

class Singleton
{
public:
  static Singleton* GetInstance()
  {
    static Singleton instance; //为了说明问题,忽略多线程。实际实现加锁和前面的懒汉式实现相同。
    return &instance;
  }

private:
  Singleton(){} //私有的构造函数
};

这样就解决了调用默认拷贝构造函数引起的问题了。同时还有另外的一种实现,既然是编译器在发现类没实现的时候给默认添加了拷贝构造函数,那我们只需要把拷贝构造函数禁止掉就可以了。所以有了如下实现

3.局部静态变量返回引用,禁止拷贝构造函数实现

#ifndef SIGLETON_H_
#define SIGLETON_H_
#include <iostream>

class Singleton
{
public:
  static Singleton& GetInstance()
  {
    static Singleton instance; //为了说明问题,忽略多线程。实际实现加锁和前面的懒汉式实现相同。
    return instance;
  }

private:
  Singleton(){} //私有的构造函数

  Singleton(const Singleton&);//只声明,不实现
  Singleton& operator = (const Singleton&);//只声明,不实现
};

这样就有效的避免了在使用单例的时候,无意中调用了拷贝构造函数。当然还有一种高大上的自动释放的实现方式是使用GC机制。

4.使用GC机制的单例实现

class Singleton
{
public:
  static Singleton* GetInstance()

private:
  class GC
  {
  public:
    ~GC()
    {
      if (Singleton::m_instance != NULL)
      {
        delete m_instance;
        m_instance = NULL;
      }
    }  
  }

  static Singleton* m_instance;
  static GC gc;
};

在使用的时候,必须要声明Singleton::GC:

Singleton::GC Singleton::GC::gc;//必须声明
//...
//do something
//...

如此使用,当你程序结束的时候,就会调用调用GC的析构函数,GC的析构函数会将你的资源释放掉。实现自动释放的功能。

到这儿,五种创建型设计模式已经介绍完了:

1.简单工厂模式(不属于24种设计模式之一)

2.工厂方法模式

3.抽象工厂模式

4.建造者模式

5.原型模式

6.单例模式

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值