探测器 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 ...
随机推荐
- Eclipse+Maven创建webapp项目<二> (转)
Eclipse+Maven创建webapp项目<二> 1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显 ...
- LeetCode204:Count Primes
Description: Count the number of prime numbers less than a non-negative number, n. 比计算少n中素数的个数. 素数又称 ...
- TimesTen更改CacheGroup管理用户ORACLE结束和TT结束password【TimesTen操作和维修基地】
password管理一直操作的一部分的安全管理和维护.CacheGroup管理用户password虽然并不复杂变化.然而,这是用于生产,改不好比较easy导致失败.简介点击这里CacheGroup管理 ...
- android最新的工具DateHelper
最新的工具DateHelper 实用程序类,.的天数来获得一个给定的月份.过了几天去习惯或.周.一个月.日期等.. 代码例如以下: import android.annotation.Suppress ...
- sails 相关文章
Node 框架之sails http://cnodejs.org/topic/555c3c82e684c4c8088a0ca1
- C#中禁止程序多开
原文:C#中禁止程序多开 方法一.使用Mutex bool createdNew; //返回是否赋予了使用线程的互斥体初始所属权 System.Threading.Mutex i ...
- Multicast on Openstack
I test multicast on openstack. I use external Router in this test. Openstack Environment: Havana (ML ...
- Intent用法
Intent是android系统中的最佳男主角,Intent翻译成中文的意思是"意图",说白了就是"我想要...",也就是说眼下运行中的Activity想要请其 ...
- SQLSERVER手动增长日志文件和数据文件
原文:SQLSERVER手动增长日志文件和数据文件 SQLSERVER手动增长日志文件和数据文件 手动增长日志文件,实际上就是修改日志文件的大小 size 的单位是MB 下面设置日志文件大小是204 ...
- 通过ccb(CocosBuilder)文件生成cocos2dx代码
在C++下使用ccb.绑定调用,成员变量.让人头疼又easy犯错. 自己用pythong写了个小程序,通过ccb文件直接生成C++代码 python我用的不多.又是随性所做.代码质量就非常差.大家多多 ...