BOOST的Singleton模版详解

boost::serialization::singleton单例的使用方式 #include "stdafx.h" #include #include #include // 使用方式1:模板参数方式 class CTest:public boost::noncopyable // 不能复制、赋值 { public: void Set(int i){ m_val = i; } void Print() const{ std::cout<<m_val<<std: 阅读详情

转自:http://blog.youkuaiyun.com/fullsail/article/details/8483106


首先要说明,这个准确说并不是BOOST的singleton实现,而是BOOST的POOL库的singleton实现。BOOST库中其实有若干个singleton模版,这个只是其中一个。但网上大部分介绍的介绍的BOOST的Singleton实现都是这个,所以大家也就默认了。而且这个的确算是比较特殊和有趣的一个实现。

网上比较有名的文章是这篇《2B程序员,普通程序员和文艺程序员的Singleton实现》 介绍,我虽然对Singleton模版无爱,但自己的项目组中也有人用这个实现,所以还是研究了一下这个实现,特别网上真正解释清楚这个东东的人并不多(包括原文),所以还是研究了一下。

1          为啥2B实现有问题

为了介绍清楚这个实现,我们还要先解释清楚为啥2B实现有问题,首先说明,2B实现和BOOST的实现都可以解决多线程调用Singleton导致多次初始化的问题。


[cpp]  view plain  copy
  1. //H文件  
  2.  template <typename T> class Singleton_2B  
  3.  {  
  4.  protected:  
  5.      typedef  T  object_type;  
  6.      //利用的是类的静态全局变量  
  7.      static T instance_;  
  8.  public:  
  9.      static T* instance()  
  10.      {  
  11.          return &instance_;  
  12.      }  
  13.  };  
  14.    
  15.  //因为是类的静态变量,必须有一个通用的声明  
  16.  template<typename T> typename Singleton_2B<T>::object_type  Singleton_2B<T>::instance_;  
  17.    
  18.  //测试的例子代码。  
  19.  class Object_2B_1  
  20.  {  
  21.        
  22.      //其实使用友元帮助我们可以让Object_2B的构造函数是protected的,从而真正实现单子的意图  
  23.      friend class Singleton_2B<Object_2B_1>;  
  24.      //注意下面用protected,大家无法构造实例  
  25.  protected:  
  26.      Object_2B_1();  
  27.      ~Object_2B_1(){};  
  28.  public:  
  29.      void do_something();  
  30.  protected:  
  31.      int data_2b_1_;  
  32.  };  
  33.    
  34.  class Object_2B_2  
  35.  {  
  36.      friend class Singleton_2B<Object_2B_2>;  
  37.  protected:  
  38.      Object_2B_2();  
  39.      ~Object_2B_2(){};  
  40.  public:  
  41.      void do_something();  
  42.  protected:  
  43.      int data_2b_2_;  
  44.  };  
  45.    
  46.  //CPP文件  
  47.  Object_2B_1::Object_2B_1():  
  48.      data_2b_1_(1)  
  49.  {  
  50.      printf("Object_2B_1::Object_2B_1() this:[%p] data_2b_1_ [%d].\n",this,data_2b_1_);  
  51.      Singleton_2B<Object_2B_2>::instance()->do_something();      
  52.  };  
  53.    
  54.  void Object_2B_1::do_something()  
  55.  {  
  56.      data_2b_1_+= 10000;  
  57.      printf("Object_2B_1::do_something() this:[%p] data_2b_1_ [%d].\n",this,data_2b_1_);  
  58.        
  59.  }  
  60.    
  61.    
  62.  Object_2B_2::Object_2B_2():  
  63.          data_2b_2_(2)  
  64.  {  
  65.      printf("Object_2B_2::Object_2B_2() this:[%p] data_2b_2_ [%d].\n",this,data_2b_2_);  
  66.      Singleton_2B<Object_2B_1>::instance()->do_something();  
  67.  };  
  68.    
  69.  void Object_2B_2::do_something()  
  70.  {  
  71.      data_2b_2_+= 10000;  
  72.      printf("Object_2B_2::do_something() this:[%p] data_2b_2_ [%d].\n",this,data_2b_2_);  
  73.  }  


如代码:Singleton_2B是一个singleton的模板封装,根据这个模版,我们实现了2个单子类,Object_2B_1和Object_2B_2,为了模仿问题,我们在其各自的构造函数里面又都调用了其他一个对象的instance函数。因为我们知道,全局和类static 变量的初始化是编译器自己控制的,我们无法干涉,所以如果假设Object_2B_1::instance_静态成员变量被先构造,他的构造函数调用里面调用Object_2B_2::instance().do_something()函数时,Object_2B_2::instance_可能还没有构造出来。从而导致问题。

但会导致什么问题呢?崩溃?不一定是,(因为静态数据区的空间应该是先分配的),而且结果这个和编译器的实现有关系,

GCC的输出结果如下:

[cpp]  view plain  copy
  1. //GCC编译器的输出如下:  
  2. Object_2B_2::Object_2B_2() this:[0046E1F4] data_2b_2_ [2].  
  3. //注意下面,do_something函数被调用了,但是没有崩溃,data_2b_1_默认被初始化为了0  
  4. Object_2B_1::do_something() this:[0046E1F0] data_2b_1_ [10000].    
  5. //注意下面,do_something函数被调用了后,构造函数才起作用,data_2b_1_又被初始化为了1,  
  6. Object_2B_1::Object_2B_1() this:[0046E1F0] data_2b_1_ [1].   
  7. Object_2B_2::do_something() this:[0046E1F4] data_2b_2_ [10002].  

VS2010的DEBUG版本的输出和GCC一致,但有意思的是Realse版本输出结果如下:

[cpp]  view plain  copy
  1. //VC++2010的release版本输出   
  2. Object_2B_2::Object_2B_2() this:[0046E1F4] data_2b_2_ [2].  
  3. //注意下面的10001,感觉就像构造函数被偷偷调用过一样。有意思。  
  4. Object_2B_1::do_something() this:[0046E1F0] data_2b_1_ [10001].    
  5. Object_2B_1::Object_2B_1() this:[0046E1F0] data_2b_1_ [1].   
  6. Object_2B_2::do_something() this:[0046E1F4] data_2b_2_ [10002].  


 

2          BOOST的实现如何规避问题

接着我们就来看看BOOST的模版是使用什么技巧,即保证多线程下不重复初始化,又让相互之间的调用更加安全。

[cpp]  view plain  copy
  1. template <typename T>  
  2. class Singleton_WY  
  3. {  
  4. private:  
  5.     struct object_creator  
  6.     {  
  7.         object_creator()   
  8.         {  
  9.             Singleton_WY<T>::instance();   
  10.         }  
  11.         inline void do_nothing() const {}  
  12.     };  
  13.     //利用类的静态对象object_creator的构造初始化,在进入main之前已经调用了instance  
  14.     //从而避免了多次初始化的问题  
  15.     static object_creator create_object_;  
  16. public:  
  17.     static T *instance()  
  18.     {  
  19.         static T obj;  
  20.         //do_nothing 是必要的,do_nothing的作用有点意思,  
  21.         //如果不加create_object_.do_nothing();这句话,在main函数前面  
  22.         //create_object_的构造函数都不会被调用,instance当然也不会被调用,  
  23.         //我的估计是模版的延迟实现的特效导致,如果没有这句话,编译器也不会实现  
  24.     // Singleton_WY<T>::object_creator,所以就会导致这个问题  
  25.         create_object_.do_nothing();  
  26.         return &obj;  
  27.     }  
  28. };  
  29. //因为create_object_是类的静态变量,必须有一个通用的声明  
  30. template <typename T>  typename Singleton_WY<T>::object_creator Singleton_WY<T>::create_object_;  
  31.   
  32. //测试的例子  
  33. class Object_WY_1  
  34. {  
  35.     //其实使用友元帮助我们可以让Object_2B的构造函数是protected的,从而真正实现单子的意图  
  36.     friend class Singleton_WY<Object_WY_1>;  
  37.     //注意下面用protected,大家无法构造实例  
  38. protected:  
  39.     Object_WY_1();  
  40.     ~Object_WY_1(){};  
  41. public:  
  42.     void do_something();  
  43. protected:  
  44.     int data_wy_1_;  
  45. };  
  46.   
  47. class Object_WY_2  
  48. {  
  49.     friend class Singleton_WY<Object_WY_2>;  
  50. protected:  
  51.     Object_WY_2();  
  52.     ~Object_WY_2(){};  
  53. public:  
  54.     void do_something();  
  55. protected:  
  56.     int data_wy_2_;  
  57. };  
  58.   
  59. //CPP代码  
  60. Object_WY_1::Object_WY_1():  
  61.     data_wy_1_(1)  
  62. {  
  63.     printf("Object_WY_1::Object_WY_1() this:[%p] data_2b_1_ [%d].\n",this,data_wy_1_);  
  64.     Singleton_WY<Object_WY_2>::instance()->do_something();      
  65. };  
  66.   
  67. void Object_WY_1::do_something()  
  68. {  
  69.     data_wy_1_+= 10000;  
  70.     printf("Object_2B_1::do_something() this:[%p] data_2b_1_ [%d].\n",this,data_wy_1_);  
  71.   
  72. }  
  73.   
  74.   
  75. Object_WY_2::Object_WY_2():  
  76.     data_wy_2_(2)  
  77. {  
  78.     printf("Object_WY_2::Object_WY_2() this:[%p] data_2b_2_ [%d].\n",this,data_wy_2_);  
  79.     Singleton_WY<Object_WY_1>::instance()->do_something();  
  80. };  
  81.   
  82. void Object_WY_2::do_something()  
  83. {  
  84.     data_wy_2_+= 10000;  
  85.     printf("Object_WY_2::do_something() this:[%p] data_2b_2_ [%d].\n",this,data_wy_2_);  
  86. }  



调用输出的结果如下,大家可以发现调用顺序正确了Object_WY_2的构造函数内部调用:Singleton_WY<Object_WY_1>::instance()函数的时候,Object_WY_1的单子实例就被创建出来了。
[cpp]  view plain  copy
  1. Object_WY_2::Object_WY_2() this:[00ECA138] data_2b_2_ [2].  
  2. Object_WY_1::Object_WY_1() this:[00ECA140] data_2b_1_ [1].  
  3. Object_WY_2::do_something() this:[00ECA138] data_2b_2_ [10002].  
  4. Object_2B_1::do_something() this:[00ECA140] data_2b_1_ [10001].  

首先BOOST的这个实现的Singleton的数据分成两个部分,一个是内部类的object_creator的静态成员creator_object_,一个是instance函数内部的静态变量static T obj;如果外部的有人调用了instance()函数,静态变量obj就会被构造出来,而静态成员creator_object_会在main函数前面构造,他的构造函数内部也调用instance(),这样就会保证静态变量一定会在main函数前面初始化出来。

到此为止,这部分还都能正常理解,但instance()函数中的这句就是有点诡异技巧的了。

create_object_.do_nothing();

其实这句话如果单独分析,并没有明确的作用,因为如果类的静态成员creator_object_的构造就应该让单子对象被初始化。但一旦你注释掉这句话,你会发现create_object_的构造函数都不会被调用。在main函数之前,什么事情都没有发生(VC++2010和GCC都一样),BOOST的代码注释只说是确保create_object_的构造被调用,但也没有明确原因。

我估计这还是和模版的编译有潜在的关系,模版都是Lazy Evaluation。所以如果编译器没有编译过create_object_.do_nothing();编译器就会漏掉create_object_的对象一切实现,也就完全不会编译Singleton_WY<T>::object_creator和Singleton_WY<T>:: create_object_代码,所以就会导致这个问题。使用dumpbin 分析去掉前后的obj文件,大约可以证明这点。所以create_object_.do_nothing();这行代码必须要有。

3          个人感觉

也许是因为我本身对Singleton的模版就不感冒,我对文艺青年的这个Singleton也没有太大胃口,

一方面是技巧性过强,我不才,do_nothing()那句话的问题我研究了半天。

二是由于他将所有的instance初始化放在了main函数前面,好处是避免了多线程多次初始化的麻烦,但也限制了初始化的多样性。一些太强的逻辑关系的情况下这招并不好。

三是这种依靠类static变量的方式,无法按需启动,回收。

四是性能,每次do_nothine也是无谓的消耗呀。

为了一个很简单的风险(多次初始化),引入一个技巧性很强的又有各种限制的东东。是否有点画蛇添足。YY。

 

告别2012,迎接2013,

 

【本文作者是雁渡寒潭,本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.NET/fullsail,否则每字一元,每图一百不讲价。对Baidu文库,360doc加价一倍】

boost::singleton_pool使用 1、与pool接口完全一致,可为简单的POD数据类型分配 内存指针; 2、它是一个单件,与整个程序的生命周期一样长; 3、singleton_pool是线程安全的。 4、主要接口: 5、简单示例: #include <iostream> #include <boost/thread.hpp> #include <boost/chrono.hpp&... 阅读详情

相关推荐

单例极致 singleton C++

四种常见的单例: 1、没有构造函数(DEFINE_SINGLETON_DEFAULT); 2、有构造函数,构造函数没有参数(DEFINE_SINGLETON_CONSTRUCT_NO_PARAM); 3、有构造函数,构造函数有没有参数版本(DEFINE_SINGLETON_CONSTRUCT_WITH_DEFAULT); 4、有构造函数,构造函数都有参数(DEFINE_SINGLETON_CONSTRUCT); 通过宏定义巧妙实现,使用也很方便!

Boost开发指南-4.6singleton

public:singleton把模板参数T实现为一个单件类,对类型T的要求是有缺省构造函数,而且在构造和析构时不能抛出异常,因为单件在main()前后构造和析构,如果发生异常则会无法捕获。singleton提供两个静态成员函数访问单件实例,可分别获得常对象和可变对象。这种区分是出于线程安全的考虑,常对象单件总是线程安全的,因为它不会改变内部状态,而可变对象单件则不是线程安全的,可能会发生线程竞争问题。

qq_36314864的博客 402

海康威视摄像机SDK二次开发--提取音频保存至文件

由于最近在开发海康威视摄像头,特此记录一下如何提取音频数据,这里主要依靠语音对讲返回的音频数据,通过回调函数写入文件中,加个WAV头即可播放,编码格式可以自己设置在代码中有注释 文件结构 其中CameraInfo内容可以参看海康威视摄像机SDK二次开发–实时预览视频流保存到指定文件中 HIKSDKSaveRealData中的内容 package ClientDemo; import ClientDemo.CameraInfo; import com.sun.jna.NativeLong; import

RichardoMu的博客 3172

boost的4种单例以及使用方法

boost4种单例及使用方法

山不在高有仙则灵,水不在深有龙则灵 817

从AI画稿到3D虚拟时装:Illustrator与Substance 3D的服装设计工作流

本文旨在解决传统服装与纺织品设计师在产品开发流程中,面临的“2D印花图案无法直观预见3D上身效果”、“物理打样成本高昂且周期漫长”的核心痛点。我们将介绍一套纯数字化的3D可视化工作流,核心是利用 Adobe Illustrator 进行矢量印花图案创作,通过 Adobe Substance 3D Sampler 将其转化为逼真的PBR(基于物理渲染)布料材质,并最终在 Adobe Substance 3D Stager 中,将该材质应用于3D服装模型,渲染出照片级的虚拟样衣。本指南将帮助设计师以极低的成本和

Kingsdesigner的博客 1396

零基础实战:YOLO检测头自定义替换全攻略

本文为零基础用户提供了YOLO检测头自定义替换的完整实战指南。通过将检测头比作汽车的“方向盘”,文章详细阐述了为何需要替换、如何寻找和集成新检测头模块、修改配置文件以及最终训练验证的全过程,旨在帮助用户针对特定任务(如小目标检测)提升模型性能。

perl8的博客 255

Boost中的单例模式

boost库实现了一个单利模式,并区分返回的是const & 还是非const &。 如果返回的是const & ,则必然已经是线程安全的。 如果返回的是非 const &,则不是线程安全的,需要自己注意加锁哦。 代码: #include using namespace std; #include "boost/serialization/singleton.hpp" using name

C++ 爱好者 make_it_simple888 1815

企业知识库AI助手的权限管理架构:如何实现细粒度控制?

在展开架构设计前,我们需要先明确“细粒度权限”的核心定义,并理解它对AI助手的特殊意义。权限管理的“粒度”,本质是权限控制的精准程度。维度粗粒度权限细粒度权限资源范围entire document(整个文档)field/paragraph(字段/段落)操作类型read/write(读/写)generate_summary/download/export(生成摘要/下载/导出)上下文约束无(静态权限)time/ip/device(时间/IP/设备)适用场景简单系统(如内部wiki)

大数据洞察的博客 1039

C++ Boost 库多个设计模式的实现

通过这些示例,可以看到 Boost 库如何帮助实现各种设计模式,利用 Boost 的功能可以简化代码,提高代码的可维护性和可扩展性。需要注意的是,使用 Boost 库时,要根据具体情况选择合适的组件,并确保正确包含相应的头文件和链接相应的库文件。同时,有些模式也可以使用 C++ 标准库中的功能实现,如。库可以实现单例模式。以下是一个简单的代理模式示例,使用 Boost 的。以下是使用 Boost 的。以下是使用 Boost 的。使用 Boost 的。使用 Boost 的。使用 Boost 的。

qq_40844444的博客 523

业态即战场:零售平台的生意模型与系统设计解构

在这篇文章中,我们从“控货、自营、联营”三种典型零售业态出发,拆解了亚马逊、阿里、京东和本地闪购平台在商品模型设计上的差异与博弈。看似简单的卖货方式背后,其实是平台在“控货权”“商品归属权”上的深层策略博弈:谁掌控商品,谁就掌控数据、流量与利润分配权。本文尝试用一套通俗但不失专业的方式,帮助产品经理和技术伙伴读懂零售平台商品模型的底层逻辑与系统设计演化路径。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 13万+

从被秒封到稳过Cloudflare!Canvas/WebGL/WebRTC多维度浏览器指纹隐身全实战

反爬和反反爬,本质上是一场持续的博弈,没有100%的隐身,只有不断升级的伪装。网上很多教程只给了个基础的噪声代码,却没讲透反爬的检测逻辑,导致你用了还是被封。这套方案的核心,不是简单的API重写,而是站在反爬的角度,模拟真实用户的所有特征,保证所有指纹的一致性、合理性、完整性。目前这套方案我用了半年,跑了上千万次请求,稳过国内国外99%的主流反爬平台,没有出现过一次因为指纹关联导致的批量封禁。大家有什么更狠的反爬场景,或者更好的伪装技巧,欢迎评论区一起交流。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1193

BOOST的Singleton模版详解(转载)

好文章,转载于fullsail博客:BOOST的Singleton模版详解 首先要说明,这个准确说并不是BOOST的singleton实现,而是BOOST的POOL库的singleton实现。BOOST库中其实有若干个singleton模版,这个只是其中一个。但网上大部分介绍的介绍的BOOST的Singleton实现都是这个,所以大家也就默认了。而且这个的确算是比较特殊和有趣的一个实现。

思考,思考,再思考~ 1211

手把手教你学Simulink--双足机器人的反步控制方法仿真

本文介绍了在Simulink中基于反步控制方法进行双足机器人仿真研究的步骤。主要内容包括:1)准备工作,包括MATLAB/Simulink安装和相关工具箱配置;2)构建简化双足机器人模型;3)设计反步控制器,阐述其递归设计原理及Lyapunov函数构造方法;4)通过MATLAB Function块实现控制逻辑并连接模型;5)仿真参数配置和结果分析。文章强调反步控制适用于非线性系统,通过逐步构造虚拟控制律保证系统稳定性,并指出需要多次调试和查阅文献来优化控制效果。该教程为研究双足机器人运动控制提供了实用的仿真

MHD0815的博客 151

boost中singleton的实现

boost::singlton实现的关键有两点 (1) sington 在进入main函数前初始化. (2)第一次使用时, singlton已得到正确的初始化(包括在static code中情况).  boost中的实现代码如下所示:   template struct singleton { private: struct object_creator { objec

guoxin_min的专栏 2297

【AUTOSAR-COM】-5.2-“Deadline Monitoring超时监控”-2-基于IPdu实现

目录 1 在CFG中配置Deadline Monitoring超时监控 1.1 参数说明 1.2 生成代码差异 2 通过一段测试代码看Deadline Monitoring超时监控 3 使用CAN盒观察Deadline Monitoring实际测试效果 3.1 Case 1:ECU开始工作时,没有收到Frame 3.2 Case 2:ECU工作中,接收的Frame丢失、 4 小结 5 结尾 关键字: DM=Deadline Monitoring超时监控 ComFirstTime...

「汽车电子助手」的博客 1788

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

boost之singleton.hpp

老版本中是文件对应在 boost/pool/detail/singleton.hpp 使用时 #include 然后 boost::details::pool::singleton_default::instance 在新版中文件已经对应到 boost/serialization/singleton.hpp 使用时需要 #include 提供了2个方法  boost::se

Special23的博客 1107

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

boost singleton

研究了一下, boost里其实有两种singleton, 还有一种冒似更简单, 精简如下  # pragma once template class boost_singleton { private: __declspec(dllexport) static T & _object; static void use(T const &) {} public: s

earthhang的专栏 653

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

ACE vs Boost: Singleton的实现及点评

文章是转载的, 点评是我加的; trade-offs of lazy initialization and run-time lock overload.

zirconsdu的专栏 3445

ACE vs Boost: Singleton的实现

以前曾经讨论过Singleton的实现,这次在对照ACE和Boost代码的时候,又重新审视了一下二者对Singleton不同的实现。其间的差别也体现了不同的编程哲学:ACE的实现更加偏重多线程中的安全和效率问题;Boost的实现则偏重于使用语言自身的特性满足Singleton模式的基本需求。 o ACE的实现 Douglas C. Schmidt在Double-Checked Lock

记事本 1567

Boost开发指南-3.10singleton_pool

public ://分配内存 static void * ordered_malloc();//归还内存 static void ordered_free(void * ptr);//释放内存 static bool purge_memory();

qq_36314864的博客 1428

几种singleton之实现解析

在工作中使用单例的时机少过,以前自己实现,后来使用boost中的serialzation/singleton.hpp的单例。singleton是一个很小巧的东西,但是它的设计良好与否,倒是能反映设计者的知识与设计哲学。   曾经有看过一些文章讲述各种实现方式,似乎并不系统与详实。今天上午同事说在单例中不都有if(xx == null) {}这样的代码吗? 我告诉他NO。 那只是一种实现方式,或

kevin的专栏 997

Boost pool库

boost pool库

x_y_y的博客 2021
上一篇: json_value.asm: No such file or directory
下一篇: log4cplus的使用
forfuture3513
博客等级 码龄15年 76粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值