iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++超详细深入分析单例模式
  • 882
分享到

C++超详细深入分析单例模式

2024-04-02 19:04:59 882人浏览 泡泡鱼
摘要

目录不能被拷贝的类c++98C++11只能在堆上创建对象的类只能在栈上创建对象的类不能被继承的类C++98C++11只能创建一个对象的类(单例模式)设计模式单例模式饿汉模式懒汉模式不

不能被拷贝的类

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

C++98

将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。


class CopyBan
{
	//...
private:
	CopyBan(const CopyBan&);
	CopyBan& operator=(const CopyBan&);
	//...
};

原因:

设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了

只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

C++11

C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。


class CopyBan
{
	//...
	CopyBan(const CopyBan&) = delete;
	CopyBan& operator = (const CopyBan&) = delete;
	//...
};

只能在堆上创建对象的类

实现方式:

将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。

提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建


class HeapOnly
{
public:
	//提供一个static公有函数创建对象,对象创建的都在堆上
	static HeapOnly* CreateObject()
	{
		return new HeapOnly;
	}
private:
	HeapOnly(){}

	//C++98 防拷贝 只声明,不实现
	HeapOnly(const HeapOnly&);
	
	//C++11
	HeapOnly(const HeapOnly&) = delete;
};

只能在栈上创建对象的类

方法一:同上将构造函数私有化,然后设计静态方法创建对象返回即可。


class StackOnly
{
public:
	StackOnly(){}
public:
	//C++11
	void* operator new(size_t size) = delete;
	void operator delete(void* p) = delete;
private:
	//C++98 防调用
	void* operator new(size_t size);
	void operator delete(void* p);
};

屏蔽new

因为new在底层调用void* operator new(size_t size)函数,只需将该函数屏蔽掉即可。注意:也要防止定位new


class StackOnly
{
public:
	StackOnly(){}
private:
	void* operator new(size_t size);
	void operator delete(void* p);
};

不能被继承的类

C++98


//C++98这种方式不够直接
//这里是可以继承的,但是Derive不能创建对象,因为Derive的构造函数必须要调用父类NonOnherit构造,但是NonInherit的构造函数私有了,私有在子类不可见,那么这里继承不会报错,继承的子类创建对象会报错
class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

C++11

final关键字,final修饰类,表示该类不能被继承。


class A final
{
	//...
};

只能创建一个对象的类(单例模式)

设计模式

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

单例模式

定义一个全局对象,大家都能用,也能保证单例,但这种方式存在很大的缺陷,你要让大家都能用,这个对象就只能定义在一个.h,如果这个.h在多个.cpp包含,那么链接会报错。全局静态,只在当前文件可见,不再是同一个对象,每个xxx.cpp中各自是一个对象。 extern可以使链接不报错,但不能保证全局只有唯一一个v,可能某个地方又重新定义了一个变量v 所以我们可以在.h中声明,在.cpp中定义,声明和定义分离。否则在.h中定义,多个cpp包含就会有多份。

某些类, 只应该具有一个对象(实例), 就称之为单例.

在很多服务器开发场景中, 经常需要让服务器加载很多的数据 (上百G) 到内存中. 此时往往要用一个单例的类来管理这些数据

单例模式有两种实现模式:饿汉实现方式和懒汉实现方式

[洗碗的例子]: 吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭. 吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗, 就是懒汉方式. 懒汉方式最核心的思想是 “延时加载”. 从而能够优化服务器的启动速度.

饿汉模式

在main函数之前,一开始就创建对象

.h:


//饿汉模式:main函数之前,一开始就创建对象
//全局只要唯一的Singleton实例对象,那么他里面的成员也就是单例的
class Singleton
{
public:
	//3.提供一个获取单例对象的static成员函数
	static Singleton& GetInstance();

	//如果vector对象是私有,想访问,只能再封装一层
	//void PushBack(int x)
	//{
	//	_v.push_back(x);
	//}
	vector<int> _v;
private:
	//vector<int> _v;

	//1.构造函数私有化,不能随意创建对象
	Singleton()
	{}

	//防拷贝
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;

	//2.类里面声明一个static Singleton对象,在cpp定义这个对象
	//保证全局只要一个唯一对象
	//这里的static类比的是全局变量,只是受类域的限制,没有改变链接属性
	static Singleton _sinst;
};

.cpp:


#include "Singleton.h"

//定义
Singleton Singleton::_sinst;

Singleton& Singleton::GetInstance()
{
	return _sinst;
}

优点:简单

缺点:main函数之前创建初始化的。如果单例对象的构造函数中要做很多工作,可能会导致进程启动慢。

且如果有多个单例类对象实例启动顺序不确定。

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。

懒汉模式

饿汉式在应用启动时就创建了 实例,饿汉式是线程安全的,是绝对单例的。懒汉式在对外提供的获取方法被调用时会实例化对象。在多线程情况下,懒汉模式不是线程安全的。

第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。


//定义
Singleton* Singleton::_spinst = nullptr;
mutex Singleton::_mtx;

Singleton& Singleton::GetInstance()
{
	//双检查加 提高效率
	if (_spinst == nullptr)
	{
		_mtx.lock();
		if (_spinst == nullptr)
		{
			//第一次调用
			_spinst = new Singleton;
		}
		_mtx.unlock();
	}

	return *_spinst;
}

void Singleton::DelInstance()
{
	if (_spinst != nullptr)
	{
		_mtx.lock();
		if (_spinst != nullptr)
		{
			delete _spinst;
			_spinst = nullptr;
		}
		_mtx.unlock();
	}
}


#pragma once
#include <vector>
#include <iOStream>
#include <mutex>
using namespace std;

//懒汉模式:第一次调用GetInstance时,才会创建初始化单例对象
//相对于饿汉,不存在可能会导致启动慢的问题,也可以控制顺序依赖的问题了
class Singleton
{
public:
	//3.提供一个获取单例对象的static成员函数
	static Singleton& GetInstance();

	//如果vector对象是私有,想访问,只能再封装一层
	//void PushBack(int x)
	//{
	//	_v.push_back(x);
	//}
	vector<int> _v;

		//或实现一个内嵌垃圾回收类
	class CGarbo {
	public:
		~CGarbo() {
			if (Singleton::_spinst)
				delete Singleton::_spinst;
		}
	};

	//定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
	static CGarbo Garbo;
	
private:
	//vector<int> _v;

	//1.构造函数私有化,不能随意创建对象
	Singleton()
	{}

	//防拷贝
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;

	//2.类里面声明一个static Singleton对象,在cpp定义这个对象
	//保证全局只要一个唯一对象
	static Singleton* _spinst;
	static mutex _mtx;
};

到此这篇关于C++ 超详细深入分析单例模式的文章就介绍到这了,更多相关C++ 单例模式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++超详细深入分析单例模式

本文链接: https://www.lsjlt.com/news/143766.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++超详细深入分析单例模式
    目录不能被拷贝的类C++98C++11只能在堆上创建对象的类只能在栈上创建对象的类不能被继承的类C++98C++11只能创建一个对象的类(单例模式)设计模式单例模式饿汉模式懒汉模式不...
    99+
    2022-11-13
  • C++单例模式实例分析
    本篇内容介绍了“C++单例模式实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!不能被拷贝的类拷贝只会放生在两个场景中:拷贝构造函数以及...
    99+
    2023-06-29
  • C#单例模式的示例分析
    这篇文章给大家分享的是有关C#单例模式的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。单例模式也是创建型模式的一种,也是23种设计模式中比较简单的一种。见名思意,在整个软件系统中,只有某个类型的一个对象,...
    99+
    2023-06-29
  • C++单例设计模式详细讲解
    目录特殊类设计只能在堆上创建对象的类请设计一个类只能在栈上创建对象请设计一个类不能被拷贝请设计一个类不能被继承请设计一个类只能创建一个对象(单例模式)懒汉模式和饿汉模式的对比特殊类设...
    99+
    2022-11-13
  • Java超详细讲解设计模式之一的单例模式
    目录单例模式1.单例模式的结构2.单例模式的实现2.1饿汉式2.2懒汉式3.单例模式的破坏3.1序列化和反序列化3.2反射单例模式 单例模式顾名思义就是单一的实例,涉及到一个单一的类...
    99+
    2022-11-13
  • 深入解析Go语言中的单例模式
    单例模式是一种常见的设计模式,它在系统中仅允许创建一个实例来控制对某些资源的访问。在 Go 语言中,实现单例模式有多种方式,本篇文章将带你深入掌握 Go 语言中的单例模式实现。什么是单例模式单例模式指仅允许创建一个对象的设计模式。它通常应用...
    99+
    2023-05-14
    Go 设计模式
  • C++深入详解单例模式与特殊类设计的实现
    目录单例模式什么是单例模式应用场景优缺点实现饿汉模式懒汉模式特殊类设计设计一个类只能在堆上创建对象方法一方法二只能在栈上创建对象方法一方法二一个类不能被继承最后单例模式 什么是单例模...
    99+
    2022-11-13
  • C++超详细分析单链表的实现与常见接口
    相信如果看完了上期顺序表的小伙伴应该发现了顺序表的诸多缺点: 中间/头部的插入删除,时间复杂度为O(N)! 增容需要申请新的空间,拷贝数据,释放旧空间,会有不少的消耗。 增容一...
    99+
    2022-11-13
  • C#单例模式引起的自定义异常举例分析
    本篇内容主要讲解“C#单例模式引起的自定义异常举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#单例模式引起的自定义异常举例分析”吧!案例代码对于单例模式,C#有个简洁的实现,采用静态的...
    99+
    2023-06-17
  • JAVA 枚举单例模式及源码分析的实例详解
    JAVA 枚举单例模式及源码分析的实例详解      单例模式的实现有很多种,网上也分析了如今实现单利模式最好用枚举,好处不外乎三点:线程安全不会因为序列化而产生新实例防止反射攻击但是貌似没...
    99+
    2023-05-31
    java 枚举 单例
  • 深入分析java与C#底层控制能力区别及示例详解
    目录比如在 C# 里面你能干的再有你还可以手动在栈上分配空间接着你想绕过 GC 直接手动分配堆内存接下来你想创建一个显式内存布局的结构 Foo从堆内存创建自然也没问题我们想自行决定动...
    99+
    2022-11-12
  • C语言编程深入理解取整取余取模问题示例分析
    目录1. 取整问题1.0向取整(C语言默认的取整方案)2.地板取整(向负无穷的方向取整)3.天花板取整(向+无穷的方向取整)4.四舍五入取整汇总例子2.取模问题 1.余数的定义2.两...
    99+
    2022-11-12
  • C++简明图解分析静态成员与单例设计模式
    目录静态成员概述静态成员数据static修饰静态成员函数const修饰静态成员const修饰成员函数静态成员案例单例模式静态成员概述 1、静态成员包括静态成员数据、静态成员函数 2、...
    99+
    2022-11-13
  • C++11中模板隐式实例化与显式实例化的定义详解分析
    目录1. 隐式实例化2. 显式实例化声明与定义3. 显式实例化的用途1. 隐式实例化 在代码中实际使用模板类构造对象或者调用模板函数时,编译器会根据调用者传给模板的实参进行模板类型推...
    99+
    2022-11-13
  • Linux中忘记root密码进入单用户模式切换运行级别的示例分析
    这篇文章将为大家详细讲解有关Linux中忘记root密码进入单用户模式切换运行级别的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。切换用户指令  su - 用户名当高权限用户切换到低权限用户的时候...
    99+
    2023-06-09
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作