C++用unordered_map查表代替if else/switch case多判断语句
一、引言
在C++中我们写判断逻辑一般会用if else或switch case语句,比如以下例子:
#include <iostream>using namespace std;class CTest
{
public:enum class ConditionType{TYPE1 = 0,TYPE2,TYPE3,};CTest() = default;~CTest() = default;void execFun(ConditionType eConditionType) //根据条件执行对应函数{switch (eConditionType) {case ConditionType::TYPE1: {func1();break;}case ConditionType::TYPE2: {func2();break;}case ConditionType::TYPE3: {func3();break;}default:break;}}void execAllFun() //执行所有函数{func1();func2();func3();}void func1() { cout << "Func1" << endl; }void func2() { cout << "Func2" << endl; }void func3() { cout << "Func3" << endl; }
};CTest gTest;int main()
{CTest::ConditionType eConditionType = CTest::ConditionType::TYPE1;gTest.execFun(eConditionType);gTest.execAllFun();
}
执行效果如下:
上面的例子很简单,我们用了switch case实现。但有如下不足:
1、swtich语句无法对字符串进行判断,只能对整形/枚举进行判断。
2、代码可读性差。上面的例子因为只有3个判断分支,所以阅读起来还好,但如果有成百上千个判断分支,那execFun函数和execAllFun函数里面的代码会变得非常臃肿,难以阅读。
3、代码可拓展性差。每新增一个分支都要修改execFun函数和execAllFun函数。
二、使用unordered_map查表代替if else和switch case语句
基于上述if else和switch case语句的不足我们可以使用unordered_map查表的方法来重构代码。
#include <iostream>
#include <unordered_map>
#include <functional>using namespace std;class CTest
{
public:enum class ConditionType{TYPE1 = 0,TYPE2,TYPE3,};CTest(){m_map[ConditionType::TYPE1] = bind(&CTest::func1, this);m_map[ConditionType::TYPE2] = bind(&CTest::func2, this);m_map[ConditionType::TYPE3] = bind(&CTest::func3, this);}~CTest() = default;void execFun(ConditionType eConditionType) //根据条件执行对应函数{auto it = m_map.find(eConditionType);if (it != m_map.end()){it->second();}}void execAllFun() //执行所有函数{for (const auto &e : m_map){e.second();}}void func1() { cout << "Func1" << endl; }void func2() { cout << "Func2" << endl; }void func3() { cout << "Func3" << endl; }
private:unordered_map<ConditionType, function<void()>> m_map;
};CTest gTest;int main()
{CTest::ConditionType eConditionType = CTest::ConditionType::TYPE1;gTest.execFun(eConditionType);gTest.execAllFun();
}
上述代码中使用了std::unordered_map而不是std::map是因为unordered_map查询速度更快,具体可以参考《map和unordered_map的区别》。当然也可以选择其它性能更高的hash表,比如google的swisstable
执行效果如下:
可以看到执行效果跟使用switch case是一摸一样的。并且有如下优点:
1、unordered_map容器类的key可以保存任意类型的数据。所以其实现的判断语句既可以对字符串进行判断,也能对整形/枚举进行判断。
2、代码拓展性强。新增分支不需要修改execFun函数和execAllFun函数,只需要改CTest类的构造函数这一个地方。
3、代码可读性强。直接在CTest类的构造函数中看unordered_map的key 关联了哪个value就可以知道整个判断逻辑。
三、进一步优化:使用单例模式
unordered_map由于建立了哈希表,所以它在最开始建立的时候比较耗时间。在实际的工程项目中我们可以把CTest类设计成单例,让unordered_map只被初始化一次。设计成单例模式的另外一个优点是把要经常使用的资源(全局变量、判断逻辑等)都放到一个地方,这样无论在代码的哪个类里面都能很方便地获取使用这些资源。
#include <iostream>
#include <unordered_map>
#include <functional>using namespace std;template<typename T>
class Singleton
{
public:static T& GetInstance(){static T instance;return instance;}Singleton(T&&) = delete;Singleton(const T&) = delete;void operator= (const T&) = delete;protected:Singleton() = default;virtual ~Singleton() = default;
};#define CT CTest::GetInstance()
class CTest : public Singleton<CTest>
{
public:enum class ConditionType{TYPE1 = 0,TYPE2,TYPE3,};CTest(){m_map[ConditionType::TYPE1] = bind(&CTest::func1, this);m_map[ConditionType::TYPE2] = bind(&CTest::func2, this);m_map[ConditionType::TYPE3] = bind(&CTest::func3, this);}~CTest() = default;void execFun(ConditionType eConditionType) //根据条件执行对应函数{auto it = m_map.find(eConditionType);if (it != m_map.end()){it->second();}}void execAllFun() //执行所有函数{for (const auto &e : m_map){e.second();}}void func1() { cout << "Func1" << endl; }void func2() { cout << "Func2" << endl; }void func3() { cout << "Func3" << endl; }
private:unordered_map<ConditionType, function<void()>> m_map;
};int main()
{CTest::ConditionType eConditionType = CTest::ConditionType::TYPE1;CT.execFun(eConditionType);CT.execAllFun();return 0;
}
执行效果如下:
四、总结
使用unordered_map查表操作代替if else/switch case语句,适用于判断分支非常多的场合。比如我们设计平台服务器,该服务器需要跟数十种不同类型的客户端/设备进行通信,涉及成百上千条通信指令。平台服务器接收通信指令后需要执行对应的回调函数,这个时候我们可以用unordered_map查表代替if else/switch case语句,来提高代码的可读性和维护性。
五、参考
《if-else VS map lookup》
《C++ 单例模式的模板实现》
C++用unordered_map查表代替if else/switch case多判断语句相关推荐
- oracle数据库查表_oracle数据库常用的99条查询语句
1. select * from emp; 2. select empno, ename, job from emp; 3. select empno 编号, ename 姓名, job 工作 fro ...
- 21张让你代码能力突飞猛进的速查表(神经网络、机器学习、可视化等)
↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:马卡斯·扬,来源:极市平台 作者丨马卡斯·扬@知乎 来源丨http ...
- 26 页高清大数据开发代码速查表,提升效率必备!【可下载】
在各大互联网公司高价抢夺数据人才的环境下,为谋求长期发展.获得高薪,很多人转行到了大数据领域.这条路人才虽缺,但要成为优秀大数据工程师并不轻松:别的不说,光学习新技术,巩固旧知识,就需要耗费大量时间精 ...
- 21张让你代码能力突飞猛进的速查表(神经网络、线性代数、可视化等)
随着深度学习的蓬勃发展,越来越多的小伙伴们开始使用python作为主打代码,python有着种类繁多的第三方库,这里为大家从网络上收集了一些代码速查表,包括深度神经网络.机器学习.数据可视化.pyth ...
- 一份火爆国外的PyCharm快捷键和Python代码速查表
各位小伙伴们,还在为记不住API发愁吗,哈哈哈,最近发现了国外大师整理了一份Python代码速查表和Pycharm快捷键sheet,火爆国外,这里分享给大家. 这个是一份Python代码速查表 下面的 ...
- 简述sed、grep和parted的速查表
下载 sed.grep和parted的速查表来整合新的流程到你的工作中. Linux 因其命令闻名,部分原因是 Linux 执行的几乎所有操作都可以从终端调用:另一部分原因是 Linux 是一个高度模 ...
- html 右边是iframe 左右结构_HTML速查表
HTML速查表 网页标题内容...... Document基本标签(Basic Tags) 最大的标题 . . . . . . . . . . . . 最小的标题 这是一个段落. (换行) (水平线) ...
- 数据科学+python+R+数据库+机器学习+(速查表)cheat sheets大全
数据科学+python+R+数据库+机器学习+(速查表)cheat sheets大全 Learn, compete, hack and get hired! 学习.竞争.精进.996. 东西永远学不完 ...
- pandas常用函数说明及速查表
pandas常用函数说明及速查表 如果你用python做开发,那么几乎肯定会使用pandas库. Pandas 是 Python 语言的一个扩展程序库,用于数据分析. Pandas 是一个开放源码.B ...
最新文章
- Gridview改变单元格颜色
- 少侠请重新来过 - Vue学习笔记(八) - Vuex
- springmvc 实例应用
- 【机器学习基础】理解关联规则算法
- oneplus 手机kali linux,OnePlus 2(一加2)刷入Kali Nethunter教程
- Java main 方法详解
- 《虚拟化与云计算》读书感(九)服务器虚拟化的其他核心技术
- 数据结构预算法(六) 数组和矩阵(1)
- rhel6中dhcp服务器配置文件,如何在CentOS/RHEL 7/6/5配置DHCP服务器
- leetcode·双指针
- Python 编写几个经典例子
- Asp.net教师管理系统
- Mysql(3):事务、锁及锁级别
- keyberos认证问题导致GSS initiate failed
- 什么百度霸屏?百度霸屏是什么意思?
- 代码审计之百家cms
- linux 下跑通pointnet++网络模型
- 李政道和杨振宁合作历程
- eclipse字体大小
- Flex布局 - 仿携程网移动端首页案列练习
热门文章
- 《Adobe Illustrator CC经典教程》—第0课0.15节使用画笔
- 利用backtrace和ucontex定位segment错误【转】
- photoshop cs之菜单栏功能介绍
- 【PaddlePaddle】【论文复现】U-GAT-IT
- 集合类 Java中的集合类解析和一些有深入的面试题
- 20130723 上海OOW第二日
- truffle unbox metacoin出现read ECONNRESET、ETIMEOUT、getaddrinfo ENOENT raw.githubusercontent.com问题
- 宇视科技android面试_宇视科技初面
- Excel笔记(4)常用函数21-34
- C# 学习笔记:委托(5):可变性