《C++Primary》阅读简要总结
三月份的主要任务之一就是阅读C++Primary这本书,终于在昨天25号下午完成了基础部分的阅读,算是对基础知识整体梳理了一遍,开始看这本书大概可以追溯到去年12月份,在那之前看了C++的入门书籍《Essential C++》,另外也完成了侯捷老师的《面向对象程序设计上和下》、以及《C++源码剖析》这三个网课的学习。到今年三月份,算是工作九个月了,才把C++Primary这本书的基础部分看完。整体进度是没有达到我去年设想的预期的,但今年的话,每个月都会安排学习任务,相信会有持续性的进步可以看到。
C++Primary这本书的话,总体上知识点非常细,会针对每种工程中遇到的情况做介绍和解释,基础部分主要学习如何正确高效地使用C++,可以概括为两大部分:一是C++语法基础,二是STL的使用。绝大多数情况下,使用C++容器总是没错的。再往后的类设计者的工具这部分内容,感觉还是要有了一定代码量之后再读才能有所收获。就放到后续再安排吧。
1. C++语法基础
熟悉C++语法是写好C++代码的基石,我也不知道该从哪里说起了,这些内容绝大多数情况下,编译器就能检查出来,不外乎变量定义、写循环判断、写函数定义,外加一些限定词令其拥有特性。等等这些,不再详述。
C++基础部分的内容还是非常重要的,围绕class可以展开说很多东西
2. STL
STL六大部件:容器、算法、迭代器、分配器、适配器、仿函数。这几个组件相互配合,可以完成非常复杂的任务,在日常编码中,也是优先使用STL已有的东西,比如Vector会大量使用,所以熟悉STL非常重要。以一个一组图像数据送入程序进行图像分割为例,来简要说明一下各个部件的作用。
2.1 容器
这里面最常用的是Vector,程序中一般性的变长数组变量都会用这个来保存,如图像所在文件夹路径或者图像路径列表文件传参到main函数后,先对其进行解析,得到所有图像路径存入vector, 如图像数据送入推理框架如onnxruntime前,数据流以void*
指到对应的内存位置,同时还需要给对应输入的维度数据,因为推理过程肯定是在三维或四维张量上进行的,维度数据肯定不能少,这些数据也可以存储到vector,到用的时候通过Vector.data()获取到内存地址。等等这些,反正就是如果你不知道该用哪种容器,那就用vector。
和vector非常相似的容器时array,但array初始化后size固定,相较于vector不够灵活,但这是相对的,如果在非常确定size的情况下或者不允许size更改的情况下,使用array越是一个好选择。
然后其他序列式容器如list(forward_list),deque,用的比较少。list的特性是插入删除指定元素非常简单O(1),不需要移动其他数据的位置。deque在对头和队尾操作数据方便,此外在线程池设计方案中,我们一般会维护一个队列用于存储已提交的任务,在线程池中的worker空闲时将队头的任务抛给worker执行,这里面还涉及到多线程的相关东西。
另外就是关联式容器了,主要包含set和map,底层主要以红黑树实现,另外还有一种使用哈希表实现的(unordered_map/set)。set只有键但map是键值对作为元素。一般map要用的比较多一些,用来存储用于查找的字典或者累计记录程序运行中产生的一些结果,如图像分割结果id映射到真实name就需要一个map。set就是一个集合。此外mutil_map和mutil_set还允许元素键重复,map和set则反之。
2.2 算法
算法部分主要包含很多常用的算法,常用如sort、find、for_each、replace(replace_if,replace_copy)、count(count_if),accumulate,binary_search。而且都是函数模板,所以可以适用于很多输入类型。总之容器和算法是单独设计的,再通过迭代器联通,即可用相应算法操作容器,底层其实是通过重载来调用不同函数进行处理的。但一般容器如果提供了对应的函数接口,则优先使用容器的function,要比算法模块提供的复杂度更低。在工作中刻意去使用这些算法,要比写循环要更高效。带_if后缀的算法要提供一个返回bool的可调用对象,作用与传入容器的每个元素或者用于两个元素对比。这里又涉及到可调用对象,其实就是可以用()运算符进行执行操作的对象:包括函数、函数指针和函数对象。
2.3 迭代器
迭代器总是和容器一起出现,而且也经常作为stl算法的参数,主要作用是用于定位容器元素位置,相当于是一种泛型指针,拥有指针的一切特性,可以++,--,也可以*解指针(我一般称为解指针,很多地方也叫做解引用、提领,底层其实引用也是用指针实现的,只是引用表现得更加优雅,不易出错,但指针更加灵活)。很少有机会去创建一个迭代器,会使用容器指针就可以了,如.begin(),.end(),.rbegin(),.rend(),还有const_begin()等等。如果创建的话,也是去维护一个指针,然后重载很多指针拥有的操作符以及上述几个函数方法。
2.4 适配器
对某一部件进行整合修改,即可获得新的部件,可称之为适配过程。STL提供的适配器分为三大类,第一类容器适配器,如stack和queue是deque的适配器,stack和queue禁用了deque的一些接口,使之表现得像另一种容器,总之就是扩充或修改原来的部件,使之特性满足特定的应用场景,同样的设计思路在设计模式之适配器adaptor中也是一样的。第二类迭代器适配器,顾名思义,对迭代器进行封装改造。第三类仿函数适配器或称为仿函数,这是STL另一个单独的部件了。
2.5 仿函数
仿函数本质是一种行为类似于函数的对象,即函数对象,对()运算符进行了重载,例如greater和less,eg.: not1(bind2nd(less<int>(), 40))
, less(a,b)本身是一个函数(或仿函数),接受两个参数用于比大小。现在用bind2nd函数适配器将第二个参数绑定为40,这样在后续传值的时候只需要给一个参数。最外层再将内部函数修饰————取反,则最终获得的函数传入值判断该值是否大于等于40.
bind2nd是之前的版本了,目前C++11应该统一使用bind,这是一个非常重的函数,eg.: fun_new = std::bind(fun_old,_1,_2)
,其中_1和_2是fun_new函数传参顺序,在这个例子中,调用fun_new(a,b)等价于调用fun_old(a,b),也可以调换传参顺序,或者提前绑定确定参数。eg.:fun_new = std::bind(fun_old,_2,_1,666)
,假设原fun_old传参数量为3,现在第三个参数确定为int值666,然后调用fun_new(a,b),即_1为a,_2为b,实际上等价于调用fun_old(b,a,666);举个例子,这部分内容在创建线程池task时会用到。
2.6 分配器
准确说应该是内存分配器,C++中动态内存的管理是一个非常容易出错的地方,C时代我们使用malloc分配内存,用free释放内存。在C++中,我们有了新的选择,用new和delete分配和释放内存,相比于malloc和free,它可以自动调用class的构造函数和析构函数,使用起来更加便捷。但底层其实还是使用malloc,malloc再调用操作系统API申请内存,申请的内存除了存储数据的区域外,还有一些头尾附加空间来存储其他必要的信息(如cookie来记录内存大小,在释放该块内存的时候会从这里提取信息来正确释放对应的空间区域)。 以上说的是用new来申请内存,其实这里说的分配器指的是另一个称为allocator的东西,不同于new,allocator允许我们将分配和初始化分离,使用allocator通常会提供更好的性能和更灵活的内存管理能力。容器如vector管理内存就是用allocator来实现的,也可以通过int*p = allocator<int>().allocate(512, int*()0)
来主动申请,但需要再通过alocator<int>().deallocate(p, 512)
来释放。实际生产中,主动这样创建非常少用,也有可能是我还未寄出到这样的需求,直接使用容器又安全又高效。如果不希望内存泄漏,直接用容器是十分明知的选择。此外,不同C++编译器在底层的实现也是不尽相同的,但暴露出来的接口一致。
当然,很多情况下我们创建类会使用new,直接完成初始化工作比较方便,并在完成相应处理后delete对应对象空间,如果在delete之前的处理过程中程序抛出异常,导致提前退出当前作用域,则在此作用域内分配的动态内存(即堆内存)失去了指向此地址的指针,导致无法完成释放,这种异常时有发生则会导致进程占用的内存越来越多,而且不好排查。一个基本原则是谁分类谁释放,还有一种解决方案是智能指针。内存泄漏排查的话,vagrind使用过几次,后续计划写篇博客详细了解一下。
3. 总结
这本书算是告一段落,学到了很多比较细的知识,还需要实践过程中不断理解,方能编码得心应手。
《C++Primary》阅读简要总结的更多相关文章
- Django forms组件里的ChoiceField、ModelChoiceField和ModelMutipleChoiceField的区别
阅读简要 首先我们要明白Django forms组件里的ChoiceField.ModelChoiceField和ModelMutipleChoiceField是继承关系 ChoiceField 1. ...
- OO课程的完结,软件工程学习的开始
目录 UML小结 阅读学习 大象:Thinking in UML UML精粹 UML和模式应用 本单元作业的架构设计 四个单元中架构设计及OO方法的演进 四个单元中测试与实践的演进 课程收获 三个具体 ...
- JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(10):通过注解(annotation)装配Bean之(@Configguration、@Component、@Value、@ComponentScan、@Autowired、@Primary、@Qualifier、@Bean)
一.通过注解(annotation)装配Bean 通过之前的学习,我们已经知道如何使用XML装配Bean,但是更多的时候已经不再推荐使用XML的方式去装配Bean,更多的时候会考虑注解(annotat ...
- Scrum团队成立,阅读《构建之法》第6~7章,并参考以下链接,发布读后感、提出问题、并简要说明你对Scrum的理解
Scrum团队成立: 团队名称:神的孩子 团队目标:短期目标,完成O2O模式的第一个平台 团队口号:我们都不是神的孩子 团队照: 角色分配 产品负责人: 许佳仪.决定开发内容和优先级排序,最大化产品 ...
- Spark SQL 代码简要阅读(基于Spark 1.1.0)
Spark SQL允许相关的查询如SQL,HiveQL或Scala运行在spark上.其核心组件是一个新的RDD:SchemaRDD,SchemaRDDs由行对象组成,并包含一个描述此行对象的每一列的 ...
- [转] Android资源管理框架(Asset Manager)简要介绍和学习计划
转自:http://blog.csdn.net/luoshengyang/article/details/8738877 Android应用程序主要由两部分内容组成:代码和资源.资源主要就是指那些与U ...
- Android资源管理框架(Asset Manager)简要介绍和学习计划
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8738877 Android应用程序主要由两部分 ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 【原】AFNetworking源码阅读(一)
[原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...
随机推荐
- Dubbo 支持服务降级吗?
以通过 dubbo:reference 中设置 mock="return null".mock 的值也可以修改 为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规 ...
- pyinstaller打包Django项目
系统:ubuntu18.04 / Centos 7自带Python3.61.安装pip3 apt-get install -y python3-pip pip3 install --u ...
- Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法 ?
1.关闭缓存 swap; 2.堆内存设置为:Min(节点内存/2, 32GB); 3.设置最大文件句柄数: 4.线程池+队列大小根据业务需要做调整: 5.磁盘存储 raid 方式--存储有条件使用 R ...
- PACT 在微服务架构中的用途是什么?
PACT 是一个开源工具,允许测试服务提供者和消费者之间的交互,与合同隔离, 从而提高微服务集成的可靠性. 微服务中的用法 用于在微服务中实现消费者驱动的合同. 测试微服务的消费者和提供者之间的消费者 ...
- 简述 Memcached 内存管理机制原理?
早期的 Memcached 内存管理方式是通过 malloc 的分配的内存,使用完后通过 free 来回收内存,这种方式容易产生内存碎片,并降低操作系统对内存的管理效 率.加重操作系统内存管理器的负担 ...
- Numpy实现多项式曲线拟合
Numpy实现多项式曲线拟合 这里可以对比matlab中的拟合方式看看matlab拟合函数的三种方法,和第一种方式很像 问题定义:对于一堆数据点(x, y),能否只根据这些数据,找出一个函数,使得函数 ...
- h5 在全屏iphonex中的适配
iphonex 已经上线有一段时间了,作为业界刘海屏幕第一款机型,导致全屏不能正常的全屏显示了,,所以需要对iphonx 适配,下面就详细说说如何适配 先看一张适配前后的图: iphonex 提供的 ...
- python-模拟页面调度LRU算法
[题目描述]所谓LRU算法,是指在发生缺页并且没有空闲主存块时,把最近最少使用的页面换出主存块,腾出地方来调入新页面. 问题描述:一进程获得n个主存块的使用权,对于给定的进程访问页面次序,问当采用LR ...
- java中到底什么是继承?
1.何为继承?What is Inheritance? 在上图中,对于车来讲,汽车就是子类.对于汽车来讲,奔驰就是子类.车是汽车的基类,超类,或说父类.到底什么是继承?马克-to-win,子类把父类的 ...
- Struts的Logic标签的用途
Struts的Logic标签可以根据特定的逻辑条件来判断网页的内容,或者循环遍历集合元素,它和HTML,Bean标签是Struts应用中最常用的三个标签. 它的功能主要是比较运算,进行字符串的匹配,判 ...