我个人整理的C++单例模式,推荐boost方式(★firecat推荐★)

简介: 我个人整理的C++单例模式,推荐boost方式(★firecat推荐★)

请重点关注三和四,boost库实现的C++单例模板类。

一、简单实现(不推荐)

// C++单例模式测试程序
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class CSingleton
{
private:
CSingleton(){;}//单例模式,禁止外部实例化
public:
//获取静态对象指针
static CSingleton *getInstance()
{ if (NULL == s_pInstance)
{
std::cout<<"new\n";
s_pInstance = new CSingleton();
}
return s_pInstance;
}
private:
static CSingleton *s_pInstance;
//类CFree被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。它的唯一作用就是在析构函数中删除CSingleton的实例。
//程序运行结束时,系统会调用CSingleton的静态成员CFree的析构函数,该析构函数会删除单例的唯一实例。
class CFree
{
public:
~CFree()
{
if (CSingleton::s_pInstance != NULL)
{
std::cout<<"delete\n";
delete CSingleton::s_pInstance;
CSingleton::s_pInstance = NULL;
}
}
};
//定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
static CFree s_Fe;
};
CSingleton* CSingleton::s_pInstance = NULL;
CSingleton::CFree CSingleton::s_Fe;//类里面的静态变量要在类外部定义,如果没有这句话,程序结束时就不会运行CFree的析构函数.
int _tmain(int argc, _TCHAR* argv[])
{
CSingleton::getInstance();
return 0;
}


以上方法是可以编译正常运行的,析构函数也能如期执行。缺点是:1、线程不安全,多线程情况下会重复调用初始化函数;2、没有使用模板,数据类型不通用。所以不推荐使用。



二、模板实现1(不推荐)


我想采用C++模板的方式,重新改写了一下:


Singleton.h文件如下

#pragma once
template<typename T>
class CSingleton
{
public:
  static T& getInstance()
  {
    if (NULL == s_pInstance)
    {
      std::cout << "new\n";
      s_pInstance = new T();
    }
    return *s_pInstance;
  }
private:
  CSingleton();//单例模式,禁止外部实例化
  ~CSingleton();
  CSingleton(const CSingleton&);
  CSingleton& operator=(const CSingleton&);
private:
  static T* s_pInstance;
  //类CFree被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。它的唯一作用就是在析构函数中删除CSingleton的实例。  
  //程序运行结束时,系统会调用CSingleton的静态成员CFree的析构函数,该析构函数会删除单例的唯一实例。  
  class CFree
  {
  public:
    ~CFree()
    {
      if (T* CSingleton<T>::s_pInstance != NULL)
      {
        std::cout << "delete\n";
        delete T* CSingleton<T>::s_pInstance;
        T* CSingleton<T>::s_pInstance = NULL;
      }
    }
  };
  //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数  
  static CFree s_Fe;
};
template<typename T> T* CSingleton<T>::s_pInstance = NULL;
template <typename T> typename CSingleton<T>::CFree CSingleton<T>::s_Fe;

main.cpp文件如下

#include <iostream>  
#include "Singleton.h"
class  A
{
public:
   A();
  ~ A();
public:
  void init()
  {
    std::cout << "hello world\n";
  }
};
 A:: A()
{
}
 A::~ A()
{
}
int main()
{
  CSingleton<A>::getInstance().init();
    return 0;
}


三、模板实现2(可行)

//C++设计模式——一个基于C++11的单例模板类
//https://blog.csdn.net/godmaycry/article/details/78458329
#include <memory>
#include <mutex>
template <typename T>
class CSingleton
{
public:
    //获取全局单例对象
    template <typename... Args>
    static std::shared_ptr<T> GetInstance(Args &&... args)
    {
        if (!s_pSelf)
        {
            std::lock_guard<std::mutex> lock(s_mutex);
            if (nullptr == s_pSelf)
            {
                s_pSelf = std::make_shared<T>(std::forward<Args>(args)...);
            }
        }
        return s_pSelf;
    }
    //主动析构单例对象(一般不需要在外部主动调用该函数,除非特殊需求)
    static void DesInstance()
    {
        if (s_pSelf)
        {
            s_pSelf.reset();
            s_pSelf = nullptr;
        }
    }
private:
    explicit CSingleton() {}
    ~CSingleton() {}
    //禁止拷贝
    CSingleton(const CSingleton &) = delete;
    CSingleton &operator=(const CSingleton &) = delete;
    CSingleton(CSingleton &&) = delete;
    CSingleton &operator=(CSingleton &&) = delete;
private:
    static std::shared_ptr<T> s_pSelf;
    static std::mutex s_mutex;
};
template <typename T>
std::shared_ptr<T> CSingleton<T>::s_pSelf = nullptr;
template <typename T>
std::mutex CSingleton<T>::s_mutex;


使用举例说明:


#include "singleton.h"


CSingleton<CToolBox>::GetInstance()->myfun();



四、来自boost C++库的实现方式(推荐)


boost库实现线程安全,避免重复初始化 --- 推荐使用


boost库有多张单例的实现,分散在不同的代码里,能够独立摘出来用的主要有以下四个:


boost/container/detail/singleton.hpp

boost/serialization/singleton.hpp

boost/thread/detail/singleton.hpp

boost/pool/singleton_pool.hpp

尤其以前两个为主。我这里只讲解第一个,\boost_1_69_0\boost\container\detail\singleton.hpp原生的代码是这样的:

// boost/container/detail/singleton.hpp
// T must be: no-throw default constructible and no-throw destructible
template <typename T>
struct singleton_default
{
  private:
    struct object_creator
    {
      // This constructor does nothing more than ensure that instance()
      //  is called before main() begins, thus creating the static
      //  T object before multithreading race issues can come up.
      object_creator() { singleton_default<T>::instance(); }
      inline void do_nothing() const { }
    };
    static object_creator create_object;
    singleton_default();
  public:
    typedef T object_type;
    // If, at any point (in user code), singleton_default<T>::instance()
    //  is called, then the following function is instantiated.
    static object_type & instance()
    {
      // This is the object that we return a reference to.
      // It is guaranteed to be created before main() begins because of
      //  the next line.
      static object_type obj;
      // The following line does nothing else than force the instantiation
      //  of singleton_default<T>::create_object, whose constructor is
      //  called before main() begins.
      create_object.do_nothing();
      return obj;
    }
};
template <typename T>
typename singleton_default<T>::object_creator
singleton_default<T>::create_object;


下面做一下中文讲解,出于习惯,我把:struct singleton_default名字修改成了class CSingleton。


其实注释已经说得很清楚了,这个实现使用了一个struct object_creator来作为类的static成员变量,单例的实体是obj,并不暴露出来,只是作为类的成员函数的static变量(local static对象)。通过create_object在main之前被执行构造来保证单例是在main之前被构造好。这个单例是利用main调用之前,程序只有一个线程,来保证单例在多线程下的唯一性。

#include "stdafx.h"
#include <iostream>
#include "singleton.h"
class QMManager
{
  //友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员),
  //当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类.
  friend class CSingleton<QMManager>; 
protected:
  QMManager() {};//这里必须写{},否则会编译出错.error LNK2019: 无法解析的外部符号 "protected: __thiscall QMManager::QMManager(void)" (??0QMManager@@IAE@XZ)
  ~QMManager() {};
public:
  void do_something()
  {
    std::cout << "hello world";
  };
};
int main()
{
  CSingleton<QMManager>::instance().do_something();
    return 0;
}
#pragma once
template <typename T>
class CSingleton
{
private:
  struct object_creator
  {
    object_creator()
    {
      CSingleton<T>::instance();
    }
    inline void do_nothing()const {}
  };
  //利用类的静态对象object_creator的构造初始化,在进入main之前已经调用了instance,
  //从而避免了多次初始化的问题
  static object_creator create_object;
public:
  typedef T object_type;
  static object_type& instance()
  {
    static object_type obj;
    //据说这个do_nothing是确保create_object构造函数被调用
    //这跟模板的编译有关
    //do_nothing 是必要的,do_nothing的作用有点意思,  
    //如果不加create_object_.do_nothing();这句话,在main函数前面,create_object_的构造函数都不会被调用,instance当然也不会被调用,  
    //我的估计是模版的延迟实现的特效导致,如果没有这句话,编译器也不会实现Singleton<T>::object_creator,所以就会导致这个问题  
    create_object.do_nothing();
    return obj;
  }
private:
  CSingleton();//单例模式,禁止外部实例化  
  ~CSingleton();
  CSingleton(const CSingleton&);
  CSingleton& operator=(const CSingleton&);
};
//因为create_object是类的静态变量,必须有一个通用的声明
template <typename T> typename CSingleton<T>::object_creator CSingleton<T>::create_object;

注意事项


所谓的单例仅仅是针对单个exe或者单个dll文件而言。如果某个单例类同时被exe和dll调用,要注意,exe和dll会各自实例化这个单例类。它们是各自独立的。所以需要共享的数据应该定义为静态成员变量。



参考文献


https://www.jianshu.com/p/333d4b37db56  boost中的单例模式(singleton)


https://coolshell.cn/articles/265.html  深入浅出单实例SINGLETON设计模式


https://blog.csdn.net/libaineu2004/article/details/79315534


 


相关文章
|
24天前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
31 1
|
1月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
61 0
|
1月前
|
设计模式 安全 测试技术
【C++】—— 单例模式详解
【C++】—— 单例模式详解
|
3月前
|
C++
C++实现单例模式-多种方式比较
单例模式,面试中经常被问到,但是很多人只会最简单的单例模型,可能连多线程都没考虑到,本文章从最简单的单例,到认为是最佳的单例模式实现方式,单例模式没有什么知识点,直接上源码
50 0
|
6月前
|
设计模式 安全 Java
特殊类设计及单例模式(C++)
特殊类设计及单例模式(C++)
65 1
|
3天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计
|
1月前
|
设计模式 存储 缓存
【ffmpeg C++ 播放器优化实战】优化你的视频播放器:使用策略模式和单例模式进行视频优化
【ffmpeg C++ 播放器优化实战】优化你的视频播放器:使用策略模式和单例模式进行视频优化
55 0
|
4月前
|
设计模式 网络协议 Java
C++ Boost 异步网络编程基础
Boost库为C++提供了强大的支持,尤其在多线程和网络编程方面。其中,Boost.Asio库是一个基于前摄器设计模式的库,用于实现高并发和网络相关的开发。Boost.Asio核心类是`io_service`,它相当于前摄模式下的`Proactor`角色。所有的IO操作都需要通过`io_service`来实现。在异步模式下,程序除了发起IO操作外,还需要定义一个用于回调的完成处理函数。`io_service`将IO操作交给操作系统执行,但它不同步等待,而是立即返回。调用`io_service`的`run`成员函数可以等待异步操作完成。当异步操作完成时,`io_service`会从操作系统获取结
80 1
C++ Boost 异步网络编程基础
|
1月前
|
设计模式 存储 缓存
设计模式之单例模式(C++)
设计模式之单例模式(C++)
22 2
|
3月前
|
设计模式 安全 编译器
c++单例模式-6种单例层层迭代优化
6种单例模式,层层迭代优化
17 1