IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 设计模式 之 单例模式 -> 正文阅读

[C++知识库]设计模式 之 单例模式

模式简介

  • 一个类只允许有一个实例,并提供一个访问该实例的全局访问点。

模式结构

单例模式主要有两种类角色:

  • 单例类:包含一个实例且能自行创建这个实例的类。
  • 访问类:使用单例的类。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5fIDpy4P-1641562964933)(assets/3-1Q1131K441K2.gif)]

实现单例的两种模式

  • 饿汉模式:程序加载时就创建一个单例
  • 懒汉模式:第一次调用 GetInstance() 方法时才去创建这个单例

非线程安全单例

// singleton_unsafe.cpp
// 单例模式(饿汉模式、线程不安全)
#include <thread>
#include <iostream>
using namespace std;

class Singleton {
protected:
	string value;
	static Singleton* instance;
	Singleton(const string& v) : value(v) { }

public:
	Singleton(Singleton& s) = delete;				// 删除拷贝函数
	void operator=(const Singleton& s) = delete;    // 删除复制函数

	static Singleton* GetInstance(const string& v) {
		if (instance == nullptr) { // 饿汉模式
			instance = new Singleton(v);
		}
		return instance;
	}

	void Print() {
		cout << value << endl;
	}
};
Singleton* Singleton::instance = nullptr;

void threadProcess(const string& s) {
	Singleton* t = Singleton::GetInstance(s);
	t->Print();
	cout << t << endl;
}

int main() {
	thread thd1 = thread(threadProcess, "bar");
	thread thd2 = thread(threadProcess, "foo");
	thd1.join();
	thd2.join();
}

输出:

// 测试输出1:正确
bar
bar
0000026D3FB3CC20
0000026D3FB3CC20
// 测试输出2:错误,线程不安全实际创建了两个实例
foobar
000001EC00BACE50

000001EC00BACD70

线程安全单例

在基础单例中,考虑到这样的一个场景:假设线程1先执行并且在未完成实例创建之前,线程2执行了条件判断,则线程2会创建一个新的实例(并且会造成内存泄漏)。

解决的方案是:在GetInstance()函数中加入锁限制每次只能有一个线程调用,改进后的代码如下:

// singleton_safe.cpp
// 单例模式(线程安全)
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;

class Singleton {
protected:
	string value;
	static mutex mtx;
	static Singleton* instance;

	Singleton(const string& v) : value(v) {
	}

public:
	Singleton(Singleton& s) = delete;				// 删除拷贝函数
	void operator=(const Singleton& s) = delete;    // 删除复制函数

	static Singleton* GetInstance(const string& v) {
		unique_lock<mutex> lck(mtx);                // 线程安全
		if (instance == nullptr) {                  // 饿汉模式
			instance = new Singleton(v);
		}
		return instance;
	}

	void Print() {
		cout << value << endl;
	}
};
mutex Singleton::mtx;
Singleton* Singleton::instance = nullptr;

void threadProcess(const string& s) {
	Singleton* t = Singleton::GetInstance(s);
	t->Print();
	cout << t << endl;
}

int main() {
	thread thd1 = thread(threadProcess, "bar");
	thread thd2 = thread(threadProcess, "foo");
	thd1.join();
	thd2.join();
}

输出

barbar

0000024B5482CFA0
0000024B5482CFA0

示例代码(Git)

应用场景

  • 某类只要求生成一个对象的时候。
  • 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
  • 需要频繁使用的一些类,使用单例可以降低系统的内存压力,减少 GC。
  • 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
  • 当对象可以被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。

模式优缺点

优点

  • 单例模式可以保证内存里只有一个实例,减少了内存的开销。
  • 可以避免对资源的多重占用。
  • 单例模式设置全局访问点,可以优化和共享资源的访问。

缺点

  • 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
  • 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
  • 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

与其他模式的关系

  • 外观模式类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
  • 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式就和单例类似了。 但这两个模式有两个根本性的不同。
    1. 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
    2. 单例对象可以是可变的。 享元对象是不可变的。
  • 抽象工厂模式生成器模式原型模式都可以用单例来实现。

参考:

  • http://c.biancheng.net/view/1338.html
  • https://refactoringguru.cn/design-patterns/singleton
  • https://www.w3cschool.cn/shejimoshi/singleton-pattern.html
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-08 13:48:12  更:2022-01-08 13:50:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:47:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码