我个人整理的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


 


相关文章
|
7天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
37 16
|
5月前
|
C++
C++单例模式
C++中使用模板实现单例模式的方法,并通过一个具体的类A示例展示了如何创建和使用单例。
48 2
|
5月前
|
缓存 网络协议 API
C/C++ StringToAddress(字符串转 boost::asio::ip::address)
通过上述步骤和示例代码,你可以轻松地在C++项目中实现从字符串到 `boost::asio::ip::address`的转换,从而充分利用Boost.Asio库进行网络编程。
181 0
|
7月前
|
安全 C++
C++ QT 单例模式
C++ QT 单例模式
134 0
|
7月前
|
设计模式 安全 IDE
C++从静态类型到单例模式
C++从静态类型到单例模式
62 0
|
8月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
100 2
|
9月前
|
设计模式 存储 缓存
C++ -- 单例模式
**摘要:** 单例模式确保一个类仅有一个实例,并提供全局访问点。为了实现单例,构造函数通常设为私有,通过静态成员函数来创建和返回实例。两种常见实现是饿汉模式(在类加载时创建实例,线程安全但可能导致不必要的内存占用)和懒汉模式(首次使用时创建,可能需线程同步)。拷贝构造函数和赋值运算符通常被禁用来防止额外实例的创建。单例模式适用于资源管理、缓存和线程池等场景。在C++中,静态成员变量和函数用于存储和访问单例实例,保证其生命周期与程序相同。
|
10月前
|
安全 程序员 C语言
从C语言到C++_37(特殊类设计和C++类型转换)单例模式(下)
从C语言到C++_37(特殊类设计和C++类型转换)单例模式
74 5
|
10月前
|
设计模式 编译器 Linux
从C语言到C++_37(特殊类设计和C++类型转换)单例模式(中)
从C语言到C++_37(特殊类设计和C++类型转换)单例模式
59 0
|
10月前
|
安全 编译器 C语言
从C语言到C++_37(特殊类设计和C++类型转换)单例模式(上)
从C语言到C++_37(特殊类设计和C++类型转换)单例模式
69 0

热门文章

最新文章