C++实现Creational - Singleton模式
来源:互联网 发布:windows gcc下载 编辑:程序博客网 时间:2024/05/23 15:27
Singleton设计模式经常被大家谈及,很多人认为该模式很简单。的确,从纯粹的设计模式的角度来看,它并不复杂,但是从实现的角度来看,其实非常不简单,尤其是用C++去实现它的时候。
一、Java版本的Singleton模式实现
我们不妨先看看在Java中实现Singleton模式的典型代码:
// Singleton设计模式典型代码
package Singleton;
publicclass Singleton
{
private Singleton(){}
privatestatic Singletoninstance =null;
publicstaticsynchronized Singleton getInstance()
{
if(instance == null)
{
instance =new Singleton();
}
returninstance;
}
}
//测试Singleton
package Singleton;
publicclass PatternClient
{
publicstaticvoid main(String args[])
{
Singleton sg = Singleton.getInstance();
}
}
从上面的代码,可以看出,在Singleton类中:
1. 构造方法是private的;
2. 有一个private的静态变量,其类型就是Singleton本身;
3. 有一个public的方法getInstance(),其返回类型是Singleton;
4. 必须注意getInstance()有关键字synchronized修饰,以提供线程安全。
下面我们来看看如何在C++中实现Singleton设计模式。
二、最简单的实现方式
先看下面的代码,并注意相关的注释:
// Singleton.h
// C++:最简单的方式实现Singleton设计模式
#include<string>
#include<iostream>
usingnamespace std;
class Singleton
{
private:
Singleton() // private构造函数
{
cout << "Singleton::Constructor" << endl;
}
static Singleton* sg; // 私有静态变量,其类型为Singleton*
// 形如Singleton sg;这样的声明会出编译时错误
public:
static Singleton* getInstance() // public成员函数getInstance()
{
cout << "Singleton::getInstance" << endl;
if(!sg)
{
sg = new Singleton(); // (1)在这个地方new了一个对象,但是在什么地方delete呢?
}
return sg;
}
};
//测试Singleton的代码:Singleton.cpp
#include"Singleton.h"
//用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象
Singleton* Singleton::sg = 0;
int main(void)
{
Singleton *sg = Singleton::getInstance();
return 0;
}
关于如何在一个类的定义中,使用类本身作为类型对成员变量进行声明的详细情况,请见:
http://blog.csdn.net/pathuang68/archive/2009/11/24/4866945.aspx
上面的Singleton的实现至少存在一个问题:
语句(1)中new了一个对象,但没有被delete,因此肯定会造成内存泄漏。而在Java语言中由于有内存回收机制,所以不存在这个问题。不过既然是Singleton,通常都是和应用程序的生命周期是基本一致的,因此,实践中可以不考虑这个“内存泄露”问题,因为它根本没有机会造成真正意义上的泄露;另一方面,从纯技术的完备性角度来看,我们则需要解决这样的问题。
三、使用auto_ptr来解决内存泄漏问题
关于auto_ptr的原理和使用方法,请参考:
http://blog.csdn.net/pathuang68/archive/2009/11/29/4898101.aspx
http://blog.csdn.net/pathuang68/archive/2009/11/29/4900321.aspx
// Singleton.h
#include<memory>
#include<string>
#include<iostream>
usingnamespace std;
// C++:使用auto_ptr实现Singleton设计模式
class Singleton
{
private:
Singleton() // private构造函数
{
cout << "Singleton::Constructor" << endl;
}
static auto_ptr<Singleton> sg; // 私有静态变量,其类型为auto_ptr<Singleton>
public:
static auto_ptr<Singleton> getInstance() // public成员函数getInstance()
{ // 返回类型为auto_ptr<Singleton>
cout << "Singleton::getInstance" << endl;
if(!sg.get()) // 判断sg所指的对象是否为空
{
// 此处不能直接写成auto_ptr<Singleton> sg(new Singleton);
auto_ptr<Singleton> temp(new Singleton);
sg = temp;
}
return sg;
}
};
// Singleton.cpp:测试Singleton的代码
#include"Singleton.h"
//用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象
auto_ptr<Singleton> Singleton::sg;
int main(void)
{
// singleton就是我们需要的对象
auto_ptr<Singleton> singleton(Singleton::getInstance());
return 0;
}
这样以来,由于引入了auto_ptr,因此不会存在内存泄漏问题。进一步地,我们还可以将Singleton类,写成模板类,这样就可以更加灵活了。为此,我们另外增加一个类Student用来测试,Singleton模板类。
// Singleton.h
#include<memory>
#include<string>
#include<iostream>
usingnamespace std;
class Student
{
public:
Student(const string name = "Andrew", const int age = 7) : name(name), age(age)
{
cout << "constructor..." << endl;
}
void print_info() const
{
cout << "Name: " << name << ", Age: " << age << endl;
}
private:
string name;
int age;
};
// Singleton模板类
template<typename T>
class Singleton
{
private:
Singleton() // private构造函数
{
cout << "Singleton::Constructor" << endl;
}
static auto_ptr<T> sg; // 私有静态变量,其类型为auto_ptr<T>
public:
static auto_ptr<T> getInstance() // public成员函数getInstance()
{ // 返回类型为auto_ptr<T>
cout << "Singleton::getInstance" << endl;
if(!sg.get()) // 判断sg所指的对象是否为空
{
// 此处不能直接写成auto_ptr<T> sg(new T);
auto_ptr<T> temp(new T);
sg = temp;
}
return sg;
}
};
// Singleton.cpp测试代码
#include"Singleton.h"
//用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象
auto_ptr<Student> Singleton<Student>::sg;
int main(void)
{
auto_ptr<Student> singleton(Singleton<Student>::getInstance());
singleton->print_info();
return 0;
}
经过测试,上面的代码证明是可行的。
四、使用boost::mutex来解决线程安全性问题
在Java代码中,有一个synchronized关键字,这个关键字的作用就是确保线程安全,很明显上面的代码尽管解决了内存泄漏的问题,但决线程安全方面的问题依然存在。
在C++语言中,本身并不存在线程的概念,需要借助一些函数库才能实现,这种函数库有很多,其中一个比较出色的就是boost中的线程库了。boost库本身是可以跨操作系统平台的。
参考下面的代码和注释:
// Singleton.h
#include<memory>
#include<string>
#include<iostream>
#include<boost/thread/thread.hpp>
#include<boost/thread/mutex.hpp>
usingnamespace std;
boost::mutex sglt_mutex;
class Student
{
public:
Student(const string name = "Andrew", const int age = 7) : name(name), age(age)
{
cout << "constructor..." << endl;
}
void print_info() const
{
cout << "Name: " << name << ", Age: " << age << endl;
}
private:
string name;
int age;
};
template<typename T>
class Singleton
{
private:
Singleton() // private构造函数
{
cout << "Singleton::Constructor" << endl;
}
static auto_ptr<T> sg; // 私有静态变量,其类型为auto_ptr<T>
public:
static auto_ptr<T> getInstance() // public成员函数getInstance()
{ // 返回类型为auto_ptr<T>
// 加锁,只有当前线程可以获取sg,其他线程均被阻塞(block)
// 直到当前线程执行sglt_mutex.unlock()
sglt_mutex.lock(); // (1)
cout << "Singleton::getInstance" << endl;
if(!sg.get()) // 判断sg所指的对象是否为空
{
// 此处不能直接写成auto_ptr<T> sg(new T);
auto_ptr<T> temp(new T);
sg = temp;
}
return sg;
}
};
// Singleton.cpp
#include"Singleton.h"
//用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象
auto_ptr<Student> Singleton<Student>::sg;
void getSingletonInstanceAndDoSomeTediousWork()
{
auto_ptr<Student> singleton(Singleton<Student>::getInstance());
// 取得相关对象后,进行各种必要的运算:
singleton->print_info();
// .... do something else
// 工作做完后,解锁。以便让别的线程获得机会。
sglt_mutex.unlock(); // (2)
// 如果没有上面这一句,则第一个获得锁的线程会无限时地阻止后续线程的运行
}
int main(void)
{
boost::thread threadA(getSingletonInstanceAndDoSomeTediousWork);
boost::thread threadB(getSingletonInstanceAndDoSomeTediousWork);
boost::thread threadC(getSingletonInstanceAndDoSomeTediousWork);
boost::thread threadD(getSingletonInstanceAndDoSomeTediousWork);
threadA.join();
threadB.join();
threadC.join();
threadD.join();
return 0;
}
上面程序的结果如下:
Singleton::getInstance
constructor...
Name: Andrew, Age: 7
Singleton::getInstance
constructor...
Name: Andrew, Age: 7
Singleton::getInstance
constructor...
Name: Andrew, Age: 7
Singleton::getInstance
constructor...
Name: Andrew, Age: 7
上述结果符合预期。每次只能有一个线程,拥有对象,其他的则被阻塞,直到当前拥有锁的线程将锁解开。
如果函数getSingletonInstanceAndDoSomeTediousWork中的语句(2)被注释掉,那么输出结果将是:
Singleton::getInstance
constructor...
Name: Andrew, Age: 7
然后就是无限时的阻塞。
进一步地,如果将类Singelton定义中的(1)的这一句,即sglt_mutex.lock();也注释掉,那么输出的结果将是:
Singleton::getInstanceSingleton::getInstanceSingleton::getInstance
constructor...constructor...
constructor...Name: Name: Name: AndrewName: AndrewAndrew, Age: Andrew, Age: , Age: 7, Age: 77
这显然是没有同步了。因此,这不是我们所需要的。
- C++实现Creational - Singleton模式
- C++实现Creational - Singleton模式
- C++实现Creational - Singleton模式
- C++实现Creational - Singleton模式
- 1. C++实现Creational - Singleton模式
- Creational模式之Singleton模式
- 【C++】实现Singleton模式
- C++实现Creational - Builder模式
- C++实现Creational - Prototype模式
- Creational模式
- C++实现Creational - Simple Factory模式
- C++实现Creational - Factory Method模式
- C++实现Creational - Abstract Factory模式
- Objective C 实现Singleton(单例)模式.
- c++--Singleton单例模式的实现
- Design Pattern - Creational Pattern - Singleton
- 创建型模式(Creational Pattern) 简单工厂 simplefactory 单例 Singleton
- Singleton模式(C++)
- Lucas定理与大组合数的取模的求法总结
- 流
- 430单片机仿真器MSP-FETU430IF遇到VCP问题不能下载程序解决办法详解
- 2.17数组循环移位
- JavaScript学习——(1)
- C++实现Creational - Singleton模式
- 软件工程课程设计方案解析
- APK_Android 为App签名(为apk签名)
- [翻译][Paper][WWW'10]Classification-Enhanced Ranking (2)
- 树状数组-简单题(HDU1166)
- 一维和二维傅里叶变换的CPP代码
- jquery
- hdu 1233 最小生成树 "还是畅通工程"
- 哈夫曼树