三月份的主要任务之一就是阅读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》阅读简要总结的更多相关文章

  1. Django forms组件里的ChoiceField、ModelChoiceField和ModelMutipleChoiceField的区别

    阅读简要 首先我们要明白Django forms组件里的ChoiceField.ModelChoiceField和ModelMutipleChoiceField是继承关系 ChoiceField 1. ...

  2. OO课程的完结,软件工程学习的开始

    目录 UML小结 阅读学习 大象:Thinking in UML UML精粹 UML和模式应用 本单元作业的架构设计 四个单元中架构设计及OO方法的演进 四个单元中测试与实践的演进 课程收获 三个具体 ...

  3. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(10):通过注解(annotation)装配Bean之(@Configguration、@Component、@Value、@ComponentScan、@Autowired、@Primary、@Qualifier、@Bean)

    一.通过注解(annotation)装配Bean 通过之前的学习,我们已经知道如何使用XML装配Bean,但是更多的时候已经不再推荐使用XML的方式去装配Bean,更多的时候会考虑注解(annotat ...

  4. Scrum团队成立,阅读《构建之法》第6~7章,并参考以下链接,发布读后感、提出问题、并简要说明你对Scrum的理解

    Scrum团队成立:  团队名称:神的孩子 团队目标:短期目标,完成O2O模式的第一个平台 团队口号:我们都不是神的孩子 团队照: 角色分配 产品负责人: 许佳仪.决定开发内容和优先级排序,最大化产品 ...

  5. Spark SQL 代码简要阅读(基于Spark 1.1.0)

    Spark SQL允许相关的查询如SQL,HiveQL或Scala运行在spark上.其核心组件是一个新的RDD:SchemaRDD,SchemaRDDs由行对象组成,并包含一个描述此行对象的每一列的 ...

  6. [转] Android资源管理框架(Asset Manager)简要介绍和学习计划

    转自:http://blog.csdn.net/luoshengyang/article/details/8738877 Android应用程序主要由两部分内容组成:代码和资源.资源主要就是指那些与U ...

  7. Android资源管理框架(Asset Manager)简要介绍和学习计划

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8738877 Android应用程序主要由两部分 ...

  8. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  9. 【原】AFNetworking源码阅读(一)

    [原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...

随机推荐

  1. Vue部署到云服务器时,访问Nginx代理出现We're sorry but books doesn't work properly without JavaScript enabled. Please enable it to continue.

    出现这个的原因,我这边的是Nginx的问题,因为没有匹配到静态文件的原因 第一个location是始终将访问的url请求定向到 index.html这个主页面 第二个location块是将index. ...

  2. ThreadLocal 是什么?有什么用?

    ThreadLocal 是一个本地线程副本变量工具类.主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的 ...

  3. 上传文件到阿里云linux服务器(windows到Linux的文件上传)

    在"运行"中输入cmd,打开控制台,切换到刚才Putty的安装目录下,我的是E:\Putty,然后输入pscp命令,我们需要这个命令来实现文件的上传.如下命令格式: F:\PuTT ...

  4. 列举 Spring Framework 的优点?

    由于 Spring Frameworks 的分层架构,用户可以自由选择自己需要的组件. Spring Framework 支持 POJO(Plain Old Java Object) 编程,从而具备持 ...

  5. Java 面试问题列表包含的主题?

    多线程,并发及线程基础 数据类型转换的基本原则 垃圾回收(GC) Java 集合框架 数组 字符串 GOF 设计模式 SOLID 抽象类与接口 Java 基础,如 equals 和 hashcode ...

  6. 用纯RUST手撸一个开源流媒体服务(RTMP/HTTPFLV/HLS)XIU

    作者工作目前在音视频流媒体行业,用了大概一年的业余时间学习Rust,并且实现了一个简单的音视频流媒体服务,虽然据说Rust已经连续多年被评为最受程序员喜欢的语言,但是在国内还是比较冷门,作者比较看好R ...

  7. 前端进阶(12) - css 的弱化与 js 的强化

    css 的弱化与 js 的强化 web 的三要素 html, css, js 在前端组件化的过程中,比如 react.vue 等组件化框架的运用,使 html 的弱化与 js 的强化 成为了一种趋势, ...

  8. H5复制粘贴双端适配的解决方案(终极版)

    前言 最终适配所有机型的方案基于clipboardjs官网https://clipboardjs.com/ 这个库由几个不同的CDN提供商托管.选择你最喜欢的:) jsDelivr <scrip ...

  9. Python窗口学习之浅尝按键触发事件

    一.窗口上敲键盘触发事件(以Enter键为例) 二.点击窗口按钮触发事件(以鼠标左键双击为例) 代码: import tkinter as tk root = tk.Tk() root.geometr ...

  10. jquery 常用选择器和方法以及遍历(超详细)

    jQuery 常用选择器和和方法 学习总结 一.JQuery 介绍 1. 什么是 jQuery 2. jQuery 版本介绍 3. jQuery 文件介绍 二.jQuery 对象 1. jQuery ...