探测器 C++ Singleton(辛格尔顿)
刚开始学习的人可能误, 误以为所有的成员变量和成员方法用于 static , 就是单例模式了:
{
public:
/* static method */
private:
static Singleton m_data; //static data member 在类中声明。在类外定义
};
Singleton Singleton::m_data;
你的类就 必须 得要有构造函数, 并确保初始化顺序).
第二, 最严重的问题, 失去了面对对象的重要特性 -- "多态", 静态成员方法不可能是 virtual 的(补充一点,静态成员方法也不可能是 const 的). Singleton类的子类没法享受 "多态" 带来的便利.
二、饿汉模式
饿汉模式 是指单例实例在程序执行时被马上执行初始化:
{
public:
static Singleton& getInstance()
{
return m_data;
}
private:
static Singleton m_data; //static data member 在类中声明。在类外定义
Singleton(){}
~Singleton(){}
};
Singleton Singleton::m_data;
这就出问题了. 由于 BSingleton m_data 静态对象可能先 ASingleton 一步调用初始化构造函数, 结果 ASingleton::getInstance() 返回的就是一个未初始化的内存区域, 程序还没跑就直接崩掉。
恩。这仅仅是理论分析的结果。以下给出一个简单的样例说明一下问题所在吧!
{
public:
static ASingleton* getInstance()
{
return &m_data;
}
void do_something()
{
cout<<"ASingleton do_something!"<<endl;
}
protected:
static ASingleton m_data; //static data member 在类中声明。在类外定义
ASingleton();
~ASingleton() {}
};
class BSingleton
{
public:
static BSingleton* getInstance()
{
return &m_data;
}
void do_something()
{
cout<<"BSingleton do_something!"<<endl;
}
protected:
static BSingleton m_data; //static data member 在类中声明,在类外定义
BSingleton();
~BSingleton() {}
};
ASingleton ASingleton::m_data;
BSingleton BSingleton::m_data;
ASingleton::ASingleton()
{
cout<<"ASingleton constructor!"<<endl;
BSingleton::getInstance()->do_something();
}
BSingleton::BSingleton()
{
cout<<"BSingleton constructor!"<<endl;
}
{
;
}
BSingleton do_something!
BSingleton constructor!
BSingleton BSingleton::m_data;
这两个定义式,那么就会依次调用 ASingleton 的构造函数 和 BSingleton 的构造函数进行初始化。
{
cout<<"ASingleton constructor!"<<endl;
BSingleton::getInstance()->do_something();
}
BSingleton 类中存在着其声明,那么还是能够调用到其 do_something 方法的。
ASingleton 单例对象 m_data 也就初始化完毕了。
BSingleton 的构造函数了。
//BSingleton BSingleton::m_data;
//改动成:
BSingleton BSingleton::m_data;
ASingleton ASingleton::m_data;
BSingleton constructor!
BSingleton do_something!
实现单例模式的致命缺点。
{
public:
static Singleton* getInstance()
{
if(! m_data) m_data = new Singleton();
return m_data;
}
private:
static Singleton* m_data; //static data member 在类中声明,在类外定义
Singleton(){}
~Singleton(){}
};
Singleton* Singleton::m_data = nullptr;
getInstance() 仅仅在第一次被调用时为 m_data 分配内存并初始化. 嗯, 看上去全部的问题都攻克了, 初始化顺序有保证, 多态也没问题.
例如说,有两个多线程同一时候进入到这种方法中,同一时候运行 if 语句的推断,那么就会出现两次两次初始化静态实例变量的情况。
{
// ... release resource
if (nullptr != m_data)
{
delete m_data;
m_data = nullptr;
}
}
public:
static Singleton& getInstance() {
static Singleton theSingleton;
return theSingleton;
}
/* more (non-static) functions here */
private:
Singleton(); // ctor hidden
Singleton(Singleton const&); // copy ctor hidden
Singleton& operator=(Singleton const&); //
assign op. hidden
~Singleton(); // dtor hidden
};
const BSingleton& b = BSingleton::getInstance();
static ASingleton theSingleton;
return theSingleton;
}
BSingleton& BSingleton::getInstance() {
const ASingleton & b = ASingleton::getInstance();
static BSingleton theSingleton;
return theSingleton;
}
Singleton 类, 当中 ASingleton BSingleton 的析构函数调用了CSingleton 实例的成员函数,
程序退出时, CSingleton 的析构函数 将首先被调用, 导致实例无效, 那么兴许 ASingleton BSingleton 的析构都将失败,
导致程序异常退出.
{
static bool constructed = false;
static uninitialized Singleton instance_;
if (!constructed) {
constructed = true;
new(&s) Singleton; //construct it
}
return instance_;
}
解决问题的办法是为指示类是否已经实例化的变量提供一个相互排斥锁 (尽管这样会减少效率).
{
Lock();
//锁自己实现 static
Singleton instance_;
UnLock();
return instance_;
}
五、终极方案
{
public:
static Singleton* getInstance()
{
static Singleton instance;
return &instance;
}
protected:
struct Object_Creator
{
Object_Creator()
{
Singleton::getInstance();
}
};
static Object_Creator _object_creator;
Singleton() {}
~Singleton() {}
};
Singleton::Object_Creator Singleton::_object_creator;
在前面的方案中:饿汉模式中,使用到了类静态成员变量,可是遇到了初始化顺序的问题; 懒汉模式中。使用到了静态局部变量,可是存在着线程安全等问题。
方法。
这样就会调用到 Singleton::getInstance()
方法初始化单例对象。那么自然 Singleton 的构造函数也就运行了。
{
public:
static Singleton* getInstance()
{
static Singleton instance;
return &instance;
}
protected:
struct Object_Creator
{
Object_Creator()
{
cout<<"Object_Creator constructor"<<endl;
Singleton::getInstance();
}
};
static Object_Creator _object_creator;
Singleton() {cout<<"Singleton constructor"<<endl;}
~Singleton() {}
};
Singleton::Object_Creator Singleton::_object_creator;
Singleton constructor
{
public:
static ASingleton* getInstance()
{
static ASingleton instance;
return &instance;
}
void do_something()
{
cout<<"ASingleton do_something!"<<endl;
}
protected:
struct Object_Creator
{
Object_Creator()
{
ASingleton::getInstance();
}
};
static Object_Creator _object_creator;
ASingleton();
~ASingleton() {}
};
class BSingleton
{
public:
static BSingleton* getInstance()
{
static BSingleton instance;
return &instance;
}
void do_something()
{
cout<<"BSingleton do_something!"<<endl;
}
protected:
struct Object_Creator
{
Object_Creator()
{
BSingleton::getInstance();
}
};
static Object_Creator _object_creator;
BSingleton();
~BSingleton() {}
};
ASingleton::Object_Creator ASingleton::_object_creator;
BSingleton::Object_Creator BSingleton::_object_creator;
ASingleton::ASingleton()
{
cout<<"ASingleton constructor!"<<endl;
BSingleton::getInstance()->do_something();
}
BSingleton::BSingleton()
{
cout<<"BSingleton constructor!"<<endl;
}
BSingleton constructor!
BSingleton do_something!
class Singleton
{
struct object_creator
{
object_creator()
{
Singleton<T>::instance();
}
inline void do_nothing() const {}
};
static object_creator create_object;
public:
typedef T object_type;
static T& instance()
{
static T obj;
//这个do_nothing是确保create_object构造函数被调用
//这跟模板的编译有关
create_object.do_nothing();
return obj;
}
};
template <typename T> typename Singleton<T>::object_creator
Singleton<T>::create_object;
class QMManager
{
protected:
QMManager() {}
~QMManager() {}
friend class Singleton<QMManager>;
public:
void do_something() {};
};
int main()
{
Singleton<QMManager>::instance().do_something();
;
}
boost 通过加入一个类似 proxy-class 的方式,实现了单例模式,可是显然添加了复杂性,在实际应用中应该依据实际情况採用适当的实现方案。
探测器 C++ Singleton(辛格尔顿)的更多相关文章
- 亮点面试题&&实现Singleton(辛格尔顿)模式-JAVA版本
称号:设计一个类.我们只能产生这个类的一个实例.(来自<剑指Offer>) 解析:仅仅能生产一个实例的类是实现Singleton(单例)模式的类型.因为设计模式在面向对象程序设计中起着举足 ...
- 设计模式——辛格尔顿(Singleton)
要想正确理解设计模式,首先必须明白它是为了解决什么问题而提出来的. 设计模式学习笔记 --Shulin 转载请注明出处:http://blog.csdn.net/zhshulin 单例模式属于设计模式 ...
- Swift辛格尔顿设计模式(SINGLETON)
本文已更新为2.0语法,具体查看:一叶单例模式 一.意图 保证一个类公有一个实例.并提供一个訪问它的全局訪问点. 二.使用场景 1.使用场景 当类仅仅能有一个实例并且客户能够从一个众所周知的訪问点訪问 ...
- 【从cocos2d-x学习设计模式】第一阶段:辛格尔顿
设计模式,它总结了前辈在许多方案重用代码.它是一个想法. 因为我们爱cocos2d-x,然后我们从去cocos2d-x在设计模式中,右一起学习!本篇解释未来辛格尔顿. 提cocos2d-x中间Dire ...
- 辛格尔顿和Android
辛格尔顿(Singleton) .singleton.h,定义类的基本成员及接口 #ifndef SINGLETON_H_INCLUDE #define SINGLETON_H_INCLUDE cla ...
- 23种设计模式--单例模式-Singleton
一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...
- 设计模式之单例模式(Singleton)
设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...
- PHP设计模式(四)单例模式(Singleton For PHP)
今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...
- The Java Enum: A Singleton Pattern [reproduced]
The singleton pattern restricts the instantiation of a class to one object. In Java, to enforce this ...
随机推荐
- 很多Python新手教程
重要提示 这不是一个教程新手程序员准备,你担任很快编程,或者没有使用1至2程序设计语言,请移步!这是一些编程经验准备.它最出名Java或C,理解命令行,Shell等待.简而言之,面向老鸟的,让老鸟高速 ...
- POJ 2485 Highways (prim最小生成树)
对于终于生成的最小生成树中最长边所连接的两点来说 不存在更短的边使得该两点以不论什么方式联通 对于本题来说 最小生成树中的最长边的边长就是使整个图联通的最长边的边长 由此可知仅仅要对给出城市所抽象出的 ...
- Win32 Windows编程 九
资源的使用 1 资源文件 图标 光标 字符串 菜单 加速键 对话框资源位图等等 资源脚本文件 - 扩展名为RC文件 定义了资源和相关文件等信息 资源编译器 - RC.exe 2 图标资源 ICON ...
- php zip文件内容比較类
php zip 文件比較类,比較两个zip文件的内容,返回新增,删除,及同样的文件列表.临时仅仅支持单层. 需求:上传一个zip文件,zip内有非常多图片文件.须要对图片文件进行一系列非常耗时的处理. ...
- table 谷歌下不出现滚动条
<table> </table> <style> table {overflow-y:scroll;max-height:152px; height:auto;} ...
- 20那天android得知
20多天的实习(事实上,一个人学习的东西)要结束, 剩下的只是读研. 这项20许多天我学到了很多东西, 对android的发展也有了一定的了解.之后写这篇文章主要完成的研究可以得知快速回升 1.安德鲁 ...
- 应用层协议系列(两)——HTTPserver之http协议分析
上一篇文章<抄nginx Httpserver设计与实现(一)--多进程和多通道IO现>中实现了一个仿照nginx的支持高并发的server.但仅仅是实现了port监听和数据接收.并没有实 ...
- UVA434 - Matty's Blocks
option=com_onlinejudge&Itemid=8&page=show_problem&category=457&problem=375&mosms ...
- fcitx
安装完成后首先面对的问题是全英文无法显示汉字和输入汉字的问题.需要找到光盘上的2个中文支持字体包安装上即可.文件名如下,注意不同版本文件明后面数字部分可能会不同,其代表版本号.下面是Red Hat E ...
- RunJS推荐用于个人使用(使用方便JS、css实时预览、编辑、管理等功能)
RunJS,在线编写.展示html.js.css代码,拥有实时预览.分享.Fork.代码高亮.自己主动完毕等多项特性,提供文件上传.多种登录方式. 地址:http://runjs.cn/ waterm ...