单例模式的c++实现
#pragma once #include <iostream>
#include <memory>
#include <Windows.h>
using namespace std;
/*************************************************************************************** 1、首先要有一个创建实例的静态函数GetInstance
2、实现的方式既可以通过new动态创建,也可以通过static静态局部变量实现
3、创建的时机既可以通过静态变量初始化时创建,也可以在调用GetInstance函数时再创建,通过静态变量的初始化的好处是
它是在进入主函数之前创建成功的可以避免多线程的问题,但是坏处就是在程序启动时初始化会拖慢启动过程。
4、为了防止通过调用构造函数创建实例,要将类的构造、复制构造和赋值构造函数设为私有的
5、GetInstance函数的返回值既可以是指针,又可以是引用,当是指针的时候要防止它在中途被delete掉,因此要将析构函数设为私有的
6、这种模式有点像全局变量,但还是有区别的,单件的作用是保证只有一份实例,而能够全局访问是它附带的功能。 ********************************************************//////////////////////////////////////
class singleton1
{
public:
static singleton1* GetInstance()
{
if(ptr == NULL)
ptr = new singleton1;
return ptr;
} static void show()
{
cout << "singleton1::show" << endl;
} private:
~singleton1()
{
cout << "dest singleton1" << endl;
}
static singleton1* ptr;
singleton1()
{
cout << "cstr singleton1" << endl;
} singleton1(const singleton1 &);
singleton1& operator=(const singleton1 &);
}; singleton1* singleton1::ptr = new singleton1; /*****************
1、在上面的实现中,使用指针时,不能销毁实例,只有当程序结束时才由系统回收,考虑将指针设计成智能指针shared_ptr,
但是智能指针的回收还是要调用析构函数,声明为public,指针随时会被delete,有很多问题,所以这种方法是不太实用
*****************/
class singleton3
{
public:
~singleton3()
{
cout << "dest singleton3" << endl;
} static singleton3* GetInstance()
{
if(ptr.get() == NULL)
ptr.reset(new singleton3);
return ptr.get();
} static void show()
{
cout << "singleton3::show" << endl;
} private:
static shared_ptr<singleton3> ptr;
singleton3(){}
singleton3(const singleton3 &);
singleton3& operator=(const singleton3 &);
}; shared_ptr<singleton3> singleton3::ptr; /****************************************
1、上面的实现都是基于new动态创建,并且返回的都是指针类型,这个实现基于静态局部变量,并且返回引用类型
2、返回引用而不是指针的好处是,不用担心中间会被delete掉
3、采用静态局部变量的好处是,内存管理交给系统,不需要手动管理
****************************************/
class singleton4
{
public:
~singleton4()
{
cout << "dest singleton4" << endl;
} static singleton4& GetInstance()
{
static singleton4 s;
return s;
} static void show()
{
cout << "singleton4::show" << endl;
} private:
singleton4(){;}
singleton4(const singleton4 &);
singleton4& operator=(const singleton4 &);
}; /***************************
1、如果是在GetInstance函数中创建实例,并且是多线程的话,如果有多个线程同时调用该函数,
则可能会创建多个实例,所以要对创建过程进行加锁处理
**************************/
CRITICAL_SECTION g_cs;
class Lock
{
public:
Lock()
{
InitializeCriticalSection(&g_cs);
} void LockOn()
{
EnterCriticalSection(&g_cs);
} void LockOff()
{
LeaveCriticalSection(&g_cs);
} ~Lock()
{
DeleteCriticalSection(&g_cs);
}
};
Lock g_lock; class singleton5
{
public:
~singleton5()
{
cout << "dest singleton5" << endl;
} static singleton5* GetInstance()
{
if(ptr == NULL)
{
//采用双重判断是为了提高效率,防止每次都要执行加锁过程
g_lock.LockOn();
if(ptr == NULL)
ptr = new singleton5;
g_lock.LockOff();
} return ptr;
} static void show()
{
cout << "singleton5::show" << endl;
} private:
static singleton5* ptr;
singleton5(){}
singleton5(const singleton5 &);
singleton5& operator=(const singleton5 &);
};
singleton5* singleton5::ptr = NULL; /******************
1、上面的实现虽然满足了多线程调用,但是实际中可能会有很多类都要设计成实例模式,
那么就需要都按照上面那样实现一遍,不能重用,下面的模板类就可以满足重用的需求
*******************************/
template <typename T>
class Singleton
{
public:
static T& Instance()
{
if (m_pInstance == NULL)
{
//Lock lock;
g_lock.LockOn();
if (m_pInstance == NULL)
{
m_pInstance = new T;
atexit(&Destroy);//将Destroy注册为程序结束时的执行函数释放内存
} //return *m_pInstance;
g_lock.LockOff();
} return *m_pInstance;
} protected:
Singleton(void)
{
cout << "cstr Singleton" << endl;
}
virtual ~Singleton(void)
{
cout << "dest Singleton" << endl;
} private:
Singleton(const Singleton& rhs)
{
cout << "copy cstr Singleton" << endl;
}
Singleton& operator = (const Singleton& rhs)
{
cout << "= cstr Singleton" << endl;
} static void Destroy()
{
if (m_pInstance != NULL)
delete m_pInstance;
m_pInstance = NULL;
} static T* m_pInstance;
}; template <typename T>
T* Singleton<T>::m_pInstance = NULL; //实际的单例类就按照下面的方式实现
class SingletonInstance : public Singleton<SingletonInstance>
{
public:
friend Singleton<SingletonInstance>;
void show()
{
cout << "SingletonInstance::show" << endl;
}
//
private:
SingletonInstance()
{
cout << "cstr SingletonInstance" << endl;
}
virtual ~SingletonInstance(void)
{
cout << "dest SingletonInstance" << endl;
} SingletonInstance(const SingletonInstance& rhs)
{
cout << "copy cstr SingletonInstance" << endl;
}
}; //测试类
class SingletonTest
{
public:
SingletonTest()
{
//singleton1& s1 = singleton1::GetInstance1();
//s1.show(); //singleton1 *p1 = singleton1::GetInstance();
//p1->show();
////delete p1; //singleton3 *p3 = singleton3::GetInstance();
//p3->show(); //singleton4 &p4 = singleton4::GetInstance();
//p4.show(); //singleton5 *p5 = singleton5::GetInstance();
//p5->show(); SingletonInstance &si = SingletonInstance::Instance();
si.show();
}
};
单例模式的c++实现的更多相关文章
- C++实现线程安全的单例模式
在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...
- 23种设计模式--单例模式-Singleton
一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...
- angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用
今天我们要讲的是ng2的路由系统. 例子
- java设计模式之--单例模式
前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...
- 设计模式C#合集--单例模式
单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...
- 设计模式之单例模式(Singleton)
设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...
- GOF23设计模式之单例模式
·核心作用: -保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. ·常见应用场景: -Windows的Task Manager(任务管理器)就是很典型的单例模式 -Windows的Recy ...
- GJM : C#设计模式(1)——单例模式
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- PHP设计模式(四)单例模式(Singleton For PHP)
今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
随机推荐
- loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移
$ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...
- Opencv3.0: undefined reference to cv::imread(cv::String const&, int)
使用opencv,编译出错: undefined reference to cv::imread(cv::String const&, int) 自opencv3.0之后,图像读取相关代码在i ...
- ElasticSearch 因为磁盘空间不够引起的数据插入错误。(message [ClusterBlockException[blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];]])
ES升级到624测试从Kettle插入数据的时候,经常提示如下错误 message [ClusterBlockException[blocked by: [FORBIDDEN/12/index rea ...
- centOS7虚拟机设置固定IP
说明:想要达到的如下效果, 1.笔记本主机IP为设置自动获取,不管什么情况下,不受虚拟机影响,只要连接外网就可以正常上网: 2.只要笔记本主机可以正常访问外网,启动虚拟机中的CentOS 7系统就 ...
- 01-复杂度2 Maximum Subsequence Sum (25 分)
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to ...
- 阿里云redisA迁移redisB迁移
./redis-port restore --input=./xxx.rdb --target=r-2zedc7c8e0557dsf4.redis.rds.aliyuncs.com:6379 --au ...
- PM2的安装和使用简介
一.简介 PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控.自动重启.负载均衡等,而且使用非常简单. 二.前期必备 node 环境 npm 三.安装 全局安装 ...
- node 基础小结
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- SQL操作Json数据
转载自: http://blog.csdn.net/yapingxin/article/details/16913275 有小改动.. 支持复杂结构的使用.. 使用Parent_ID来对应Object ...
- DataBind()方法实现数据绑定
在为.aspx页上的对象设置了特定数据源之后,必须将数据绑定到这些数据源上.可以使用“Page.DataBind()”或“控件.DataBind()”方法将数据绑定到数据源上. 主要差别在于:调用Pa ...