第一部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 c++ 基础
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C和C++的区别
- C是面向过程的语言<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 是一个结构化的语言<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 考虑如何通过一个过程对输入进行处理得到输出<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; C++是面向对象的语言<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 主要特征是“封装<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 继承和多态”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 封装隐藏了实现细节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使得代码模块化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 派生类可以继承父类的数据和方法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 扩展了已经存在的模块<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 实现了代码重用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 多态则是“一个接口<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 多种实现”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 通过派生类重写父类的虚函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 实现了接口的重用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - C和C++动态管理内存的方法不一样<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , C是使用malloc/free<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而C++除此之外还有new/delete关键字<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - C++中有引用<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , C中不存在引用的概念
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++中指针和引用的区别
- 指针有自己的一块空间<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而引用只是一个别名<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 使用 sizeof 看一个指针的大小为4字节<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 32位<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果要是64位的话指针为8字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 而引用则是被引用对象的大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 指针可以被初始化为 NULL<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而引用必须被初始化且必须是一个已有对象的引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 作为参数传递时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 指针需要被解引用才可以对对象进行操作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而直接对引用的修改都会改变引用所指向的对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 指针在使用中可以指向其他对象<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是引用只能是一个对象的引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不能被改变<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 指针可以是多级<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而引用没有分级<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 如果返回动态分配内存的对象或者内存<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 必须使用指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 引用可能引起内存泄漏<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
引用占用内存空间吗<span class=<h-char class=
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 结构体struct和共同体union<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 联合<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) 的区别
结构体<span class=<h-char class=
- 结构体中的每个成员都有自己独立的地址<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 它们是同时存在的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 共同体中的所有成员占用同一段内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 它们不能同时存在<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - sizeof(struct)是内存对齐后所有成员长度的总和<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , sizeof(union)是内存对齐后最长数据成员的长度<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
结构体为什么要内存对齐呢<span class=<h-char class=
- 平台原因<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 移植原因<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 不是所有的硬件平台都能访问任意地址上的任意数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 某些硬件平台只能在某些地址处取某些特定类型的数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 否则抛出硬件异常 - 硬件原因<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 经过内存对齐之后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , CPU的内存访问速度大大提升<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 struct 和 class 的区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- 首先说一下C中的结构体和C++中的结构体的异同<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 
- C++中 struct 与 class 的区别<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 内部成员变量及成员函数的默认访问属性<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : struct 默认防控属性是 public 的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 class 默认的访问属性是private的 继承关系中默认访问属性的区别<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 在继承关系<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , struct 默认是 public 的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 class 是 private class这个关键字还可用于定义模板参数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就等同于 typename<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 而strcut不用与定义模板参数
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 #define和const的区别
- #define定义的常量没有类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所给出的是一个立即数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; const定义的常量有类型名字<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存放在静态区域 - 处理阶段不同<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , #define定义的宏变量在预处理时进行替换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可能有多个拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , const所定义的变量在编译时确定其值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只有一个拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - #define定义的常量是不可以用指针去指向<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , const定义的常量可以用指针去指向该常量的地址 - #define可以定义简单的函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , const不可以定义函数
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 重载overload<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 覆盖<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 重写<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) override<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 隐藏<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 重定义<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) overwrite<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 这三者之间的区别
- overload<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 将语义相近的几个函数用同一个名字表示<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是参数列表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 参数的类型<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 个数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 顺序不同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 不同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这就是函数重载<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 返回值类型可以不同 特征<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 相同范围<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 同一个类中<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 、 函数名字相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 参数不同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 virtual关键字可有可无 - override<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 派生类覆盖基类的虚函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 实现接口的重用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 返回值类型必须相同 特征<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 不同范围<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 基类和派生类<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 、 函数名字相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 参数相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 基类中必须有virtual关键字<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 必须是虚函数<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) - overwrite<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 派生类屏蔽了其同名的基类函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 返回值类型可以不同 特征<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 不同范围<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 基类和派生类<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 、 函数名字相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 参数不同或者参数相同且无virtual关键字
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 new 和 delete 是如何实现的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 与 malloc 和 free有什么异同<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
new操作针对数据类型的处理<span class=<h-char class=
- 简单数据类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 包括基本数据类型和不需要构造函数的类型<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 简单类型直接调用 operator new 分配内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 可以通过new_handler 来处理 new 失败的情况<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; new 分配失败的时候不像 malloc 那样返回 NULL<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 它直接抛出异常<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ bad_alloc<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 要判断是否 分配成功应该用异常捕获的机制<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 复杂数据类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 需要由构造函数初始化对象<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) new 复杂数据类型的时候先调用operator new<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后在分配的内存上调用构造函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
delete也分为两种情况<span class=<h-char class=
- 简单数据类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 包括基本数据类型和不需要析构函数的类型<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) delete简单数据类型默认只是调用free函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 复杂数据类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 需要由析构函数销毁对象<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) delete复杂数据类型先调用析构函数再调用operator delete<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
与 malloc 和 free 的区别<span class=<h-char class=
- 属性上<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : new / delete 是c++关键字<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需要编译器支持<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 malloc/free是库函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需要c的头文件支持<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 参数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 使用new操作符申请内存分配时无须制定内存块的大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 编译器会根据类型信息自行计算<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而mallco则需要显式地指出所需内存的尺寸<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 返回类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : new操作符内存分配成功时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 返回的是对象类型的指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 类型严格与对象匹配<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 故new是符合类型安全性的操作符<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而malloc内存成功分配返回的是void *<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需要通过类型转换将其转换为我们需要的类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 分配失败时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : new内存分配失败时抛出bad_alloc异常<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; malloc分配内存失败时返回 NULL<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 自定义类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : new会先调用operator new函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 申请足够的内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 通常底层使用malloc实现<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 然后调用类型的构造函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 初始化成员变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 最后返回自定义类型指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 delete先调用析构函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后调用operator delete函数释放内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 通常底层使用free实现<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 malloc/free是库函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只能动态的申请和释放内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 无法强制要求其做自定义类型对象构造和析构工作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 重载<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : C++允许重载 new/delete 操作符<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而malloc为库函数不允许重载<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 内存区域<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : new操作符从自由存储区<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ free store<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 上为对象动态分配内存空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而malloc函数从堆上动态分配内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 其中自由存储区为<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : C++基于new操作符的一个抽象概念<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 凡是通过new操作符进行内存申请<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 该内存即为自由存储区<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而堆是操作系统中的术语<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 是操作系统所维护的一块特殊内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 用于程序的内存动态分配<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , C语言使用malloc从堆上分配内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使用free释放已分配的对应内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 自由存储区不等于堆<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如上所述<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 布局new就可以不位于堆中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
既然有了malloc/free<span class=<h-char class=
8<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 delete和delete[]的区别
delete只会调用一次析构函数<span class=<h-char class=
9<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 const知道吗<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 解释一下其作用
const修饰类的成员变量<span class=<h-char class=
10<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 关键字static的作用
- 函数体内<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : static 修饰的局部变量作用范围为该函数体<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不同于auto变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其内存只被分配一次<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因此其值在下次调用的时候维持了上次的值 - 模块内<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : static修饰全局变量或全局函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以被模块内的所有函数访问<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是不能被模块外的其他函数访问<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使用范围限制在声明它的模块内 - 类中<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 修饰成员变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 表示该变量属于整个类所有<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对类的所有对象只有一份拷贝 - 类中<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 修饰成员函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 表示该函数属于整个类所有<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不接受this指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只能访问类中的static成员变量 注意和const的区别<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ! <h-char class= bd bd-beg“ >“ ! <h-char class= bd bd-beg“ >“ ! const强调值不能被修改<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而static强调唯一的拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对所有类的对象
11<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 堆和栈的区别
- 堆栈空间分配区别<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 栈<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 操作系统<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 由操作系统自动分配释放 <span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存放函数的参数值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 局部变量的值等<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 其操作方式类似于数据结构中的栈<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 堆<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 操作系统<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 一般由程序员分配释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 若程序员不释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 程序结束时可能由OS回收<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 分配方式倒是类似于链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 堆栈的缓存方式区别 栈<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 是内存中存储值类型的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 大小为2M<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ window<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , linux下默认为8M<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以更改<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 超出则会报错<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 内存溢出<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 堆<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 内存中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存储的是引用数据类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 引用数据类型无法确定大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 堆实际上是一个在内存中使用到内存中零散空间的链表结构的存储空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 堆的大小由引用类型的大小直接决定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 引用类型的大小的变化直接影响到堆的变化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 堆栈数据结构上的区别 堆<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 数据结构<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 堆可以被看成是一棵树<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 堆排序<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 栈<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 数据结构<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 一种先进后出的数据结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
C++内存区域中堆和栈的区别<span class=<h-char class=
堆和自由存储区的区别<span class=<h-char class=
12<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 #include<file.h> #include <span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ file.h<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 的区别
前者是从标准库路径寻找 后者是从当前工作路径
13<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么是内存泄漏<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 面对内存泄漏和指针越界<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 你有哪些方法<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
动态分配内存所开辟的空间<span class=<h-char class=
14<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 定义和声明的区别
为变量分配地址和存储空间的称为定义<span class=<h-char class=
15<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++文件编译与执行的四个阶段
- 预处理<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 根据文件中的预处理指令来修改源文件的内容 - 编译<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 编译成汇编代码 - 汇编<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 把汇编代码翻译成目标机器指令 - 链接<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 链接目标代码生成可执行程序
16<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++的内存管理
在C++中<span class=<h-char class=
- 堆是操作系统维护的一块内存<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 堆与自由存储区并不等价<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
全局/静态存储区<span class=<h-char class=
17<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++的四种强制转换
类型转化机制可以分为隐式类型转换和显示类型转化<span class=<h-char class=
- static_cast <span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 编译时期的静态类型检查static_cast静态转换相当于C语言中的强制转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但不能实现普通指针数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 空指针除外<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 的强制转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 一般用于父类和子类指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 引用间的相互转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 没有运行时类型检查来保证转换的安全性<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
①用于类层次结构中基类<span class=<h-char class=
- 进行上行转换<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 把派生类的指针或引用转换成基类表示<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 是安全的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 进行下行转换<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 把基类指针或引用转换成派生类表示<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 由于没有动态类型检查<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以是不安全的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是编译器不会报错<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
②用于基本数据类型之间的转换<span class=<h-char class=
- dynamic_cast<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 运行时的检查 动态转换的类型和操作数必须是完整类类型或空指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 空引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 说人话就是说<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只能用于类间转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 支持类间交叉转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不能操作普通数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 主要用于类层次结构中基类<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 父类<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 和派生类<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 子类<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 之间指针或引用的转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , ①进行上行转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 把派生类的指针或引用转换成基类表示<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 是安全的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 允许转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; ②进行下行转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 把基类指针或引用转换成派生类表示<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 由于没有动态类型检查<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以是不安全的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不允许转化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 编译器会报错<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; ③发生多态时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 允许互相转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 ④无继承关系的类之间也可以相互转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 类之间的交叉转换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 ⑤如果dynamic_cast语句的转换目标是指针类型并且失败了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则结果为0<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如果转换目标是引用类型并且失败了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则dynamic_cast运算符将抛出一个std::bad_cast异常 - const_cast const_cast用于强制去掉不能被修改的常数特性<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其去除常量性的对象一般为指针或引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - reinterpret_cast 在C++语言中<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , reinterpret_cast主要有几种强制转换用途<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将指针或引用转换为一个足够长度的整型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 将整型转换为指针或引用类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 更详细见 C++的四种强制转换 - 为什么不使用C的强制转换 <span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ? C的强制转换表面上看起来功能强大什么都能转<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是转化不够明确<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不能进行错误检查<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 容易出错<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
18<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 extern“C”作用
extern <span class=<h-char class=
19<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 typdef和define区别
#define是预处理命令<span class=<h-char class=
20<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 引用作为函数参数以及返回值的好处
对比值传递<span class=<h-char class=
- 在函数内部可以对此参数进行修改
- 提高函数调用和运行的效率<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 所以没有了传值和生成副本的时间和空间消耗<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 值传递<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 形参是实参的拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 改变形参的值并不会影响外部实参的值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 从被调用函数的角度来说<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 值传递是单向的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 实参->形参<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 参数的值只能传入<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不能传出<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 当函数内部需要修改参数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并且不希望这个改变影响调用者时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 采用值传递<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 指针传递<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 形参为指向实参地址的指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当对形参的指向操作时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就相当于对实参本身进行的操作 引用传递<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 形参相当于是实参的“别名”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对形参的操作其实就是对实参的操作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在引用传递过程中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是这时存放的是由主调函数放进来的实参变量的地址<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 被调函数对形参的任何操作都被处理成间接寻址<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 即通过栈中存放的地址访问主调函数中的实参变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 正因为如此<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被调函数对形参做的任何操作都影响了主调函数中的实参变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 用引用作为返回值最大的好处就是在内存中不产生被返回值的副本<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
但是有以下的限制<span class=<h-char class=
- 不能返回局部变量的引用<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 因为函数返回以后局部变量就会被销毁 - 不能返回函数内部new分配的内存的引用<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 虽然不存在局部变量的被动销毁问题<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可对于这种情况<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 返回函数内部new分配内存的引用<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 又面临其它尴尬局面<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 例如<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被函数返回的引用只是作为一 个临时变量出现<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而没有被赋予一个实际的变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么这个引用所指向的空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 由new分配<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 就无法释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 造成memory leak - 可以返回类成员的引用<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是最好是const<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 因为如果其他对象可以获得该属性的非常量的引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么对该属性的单纯赋值就会破坏业务规则的完整性<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
21<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么是野指针
野指针不是NULL指针<span class=<h-char class=
- 指针变量没有被初始化
- 指针指向的内存被释放了<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是指针没有置NULL - 指针超过了变量了的作用范围<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 比如b[10]<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 指针b+11
22<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++中内存泄漏的几种情况
内存泄漏是指动态分配的堆内存由于某种原因程序未释放或无法释放<span class=<h-char class=
- 类的构造函数和析构函数中new和delete没有配套
- 在释放对象数组时没有使用delete[]<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使用了delete - 没有将基类的析构函数定义为虚函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当基类指针指向子类对象时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果基类的析构函数不是virtual<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么子类的析构函数将不会被调用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 子类的资源没有正确释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因此造成内存泄露 - 没有正确的清楚嵌套的对象指针
23<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 栈溢出的原因以及解决方法
栈溢出是指函数中的局部变量造成的溢出<span class=<h-char class=
- 函数调用层次过深,每调用一次,函数的参数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 局部变量等信息就压一次栈 - 局部变量体积太大<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
解决办法大致说来也有两种<span class=<h-char class=
- 增加栈内存的数目<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 如果是不超过栈大小但是分配值小的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就增大分配的大小 - 使用堆内存<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 具体实现由很多种方法可以直接把数组定义改成指针,然后动态申请内存;也可以把局部变量变成全局变量,一个偷懒的办法是直接在定义前边加个static,呵呵,直接变成静态变量(实质就是全局变量)
24<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 左值和右值
不是很严谨的来说<span class=<h-char class=
25<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 左值引用与右值引用
左值引用就是我们通常所说的引用<span class=<h-char class=
|
右值引用是 C++11 新增的特性<span class=<h-char class=
- 右值引用支持移动语义的实现<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以减少拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 提升程序的执行效率<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 右值引用可以使重载函数变得更加简洁<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 右值引用可以适用 const T& 和 T& 形式的参数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
|
在汇编层面右值引用做的事情和常引用是相同的<span class=<h-char class=
26<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 头文件中的 ifndef/define/endif 是干什么用的? 该用法和 program once 的区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
相同点<span class=<h-char class=
- ifndef 由语言本身提供支持<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是 program once 一般由编译器提供支持<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 也就是说<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 有可能出现编译器不支持的情况(主要是比较老的编译器)<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 通常运行速度上 ifndef 一般慢于 program once<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 特别是在大型项目上<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 区别会比较明显<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以越来越多的编译器开始支持 program once<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - ifndef 作用于某一段被包含<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ define 和 endif 之间<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 的代码<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 program once 则是针对包含该语句的文件<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这也是为什么 program once 速度更快的原因<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 如果用 ifndef 包含某一段宏定义<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当这个宏名字出现“撞车”时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可能会出现这个宏在程序中提示宏未定义的情况<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 在编写大型程序时特别需要注意<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为有很多程序员在同时写代码<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 相反由于program once 针对整个文件<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因此它不存在宏名字“撞车”的情况<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是如果某个头文件被多次拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , program once 无法保证不被多次包含<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为program once 是从物理上判断是不是同一个头文件<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而不是从内容上<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
27<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 指针数组和数组指针的区别
数组指针<span class=<h-char class=
- 数组指针<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 是指向数组的指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其本质为指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 形式如下<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如 int (*p)[n]<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , p即为指向数组的指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , ()优先级高<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 首先说明p是一个指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 指向一个整型的一维数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这个一维数组的长度是n<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 也可以说是p的步长<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 也就是说执行p+1时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , p要跨过n个整型数据的长度<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 数组指针是指向数组首元素的地址的指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其本质为指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以看成是二级指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
|
- 指针数组<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在C语言和C++中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 数组元素全为指针的数组称为指针数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其中一维指针数组的定义形式如下<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 指针数组中每一个元素均为指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其本质为数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如 int _p[n]<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , []优先级高<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 先与p结合成为一个数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 再由int_说明这是一个整型指针数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 它有n个指针类型的数组元素<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 这里执行p+1时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则p指向下一个数组元素<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这样赋值是错误的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : p=a<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 因为p是个不可知的表示<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只存在p[0]<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 p[1]<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 但可以这样 _p=a; 这里_p表示指针数组第一个元素的值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , a的首地址的值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
|
28<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++是不是类型安全的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
不是<span class=<h-char class=
29<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 main函数执行之前<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 还会执行什么代码<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
全局对象的构造函数会在main函数之前执行<span class=<h-char class=
30<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 全局变量和局部变量有什么区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 是怎么实现的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 操作系统和编译器是怎么知道的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
生命周期不同<span class=<h-char class=
31<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 关于sizeof小结的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >。
答<span class=<h-char class=
- sizeof不计算static变量占得内存<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 32位系统的指针的大小是4个字节<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 64位系统的指针是8字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而不用管指针类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - char型占1个字节<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , int占4个字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , short int占2个字节 long int占4个字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , float占4字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , double占8字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , string占4字节 一个空类占1个字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 单一继承的空类占1个字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 虚继承涉及到虚指针所以占4个字节 - 数组的长度<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 若指定了数组长度<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则不看元素个数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 总字节数=数组长度*sizeof<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 元素类型<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 若没有指定长度<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则按实际元素个数类确定 Ps<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 若是字符数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则应考虑末尾的空字符<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 结构体对象的长度 在默认情况下<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 为方便对结构体内元素的访问和管理<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当结构体内元素长度小于处理器位数的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 便以结构体内最长的数据元素的长度为对齐单位<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 即为其整数倍<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 若结构体内元素长度大于处理器位数则以处理器位数为单位对齐<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - unsigned影响的只是最高位的意义<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 数据长度不会改变<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以sizeof<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ unsigned int<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) =4 - 自定义类型的sizeof取值等于它的类型原型取sizeof
- 对函数使用sizeof<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在编译阶段会被函数的返回值的类型代替 - sizeof后如果是类型名则必须加括号<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果是变量名可以不加括号<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这是因为sizeof是运算符 - 当使用结构类型或者变量时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , sizeof返回实际的大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 当使用静态数组时返回数组的全部大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , sizeof不能返回动态数组或者外部数组的尺寸
32<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 sizeof 和 strlen 的区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- sizeof 是一个操作符<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , strlen 是库函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - sizeof 的参数可以是数据的类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 也可以是变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 而 strlen 只能以结尾为 ‘\0’ 的字符串做参数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 数组做 siezeof 的参数不退化<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 传递给 strlen 就退化为指针了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 编译器在编译时就计算出了 sizeof 的结果<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 strlen 函数必须在运行时才能计算出来<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而且 sizeof 计算的是数据类型占内存的大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 strlen 计算的是字符串实际的长度
33<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 说说内联函数
函数调用是有时间和空间开销的<span class=<h-char class=
34<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C/C++的存储期
C对象有4种存储期<span class=<h-char class=
35<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 流操作符重载为什么返回引用
在程序中<span class=<h-char class=
36<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 全局变量和局部变量有什么区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 实怎么实现的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 操作系统和编译器是怎么知道的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- 生命周期不同<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 全局变量随主程序创建和创建<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 随主程序销毁而销毁 局部变量在局部函数内部<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 甚至局部循环体等内部存在<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 退出就不存在<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 内存中分配在全局数据区 - 使用方式不同<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 通过声明后全局变量程序的各个部分都可以用到<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 局部变量只能在局部使用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 分配在栈区
操作系统和编译器通过内存分配的位置来知道的<span class=<h-char class=
第二部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 c++ 类相关
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么是面向对象<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( OOP<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) <h-char class=“ bd bd-beg“ >? 面向对象的意义<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
Object Oriented Programming, 面向对象是一种对现实世界理解和抽象的方法<span class=<h-char class=
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 解释下封装<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 继承和多态<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
封装<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 封装是实现面向对象程序设计的第一步<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 封装就是将数据或函数等集合在一个个的单元中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 我们称之为类<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 封装的意义在于保护或者防止代码<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 数据<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 被我们无意中破坏<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 从封装的角度看<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , public<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , private 和 protected 属性的特点如下<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 不管哪种属性<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 内类都是可以访问的 - public 是一种暴露的手段<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 比如暴露接口<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 类的对象可以访问 - private 是一种隐藏的手段<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 类的对象不能访问 - protected 成员<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : - 和 public 一样可以被子类继承
- 和 private 一样不能在类外被直接调用
- 特例<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 在衍生类中可以通过衍生类对象访问
- 不管哪种属性<span class=<h-char class=
继承<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 继承主要实现重用代码<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 节省开发时间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 子类可以继承父类的一些东西<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - a.公有继承(public) 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 它们都保持原有的状态<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 基类的私有成员仍然是私有的<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不能被这个派生类的子类所访问<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 - b.私有继承(private) 私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 并且不能被这个派生类的子类所访问<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 - c.保护继承(protected) 保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 并且只能被它的派生类成员函数或友元访问<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 基类的私有成员仍然是私有的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 这里特别提一下虚继承<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 虚继承是解决C++多重继承问题<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 其一<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 浪费存储空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 第二<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存在二义性问题<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 的一种手段<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 比如菱形继承<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 典型的应用就是 iostream, 其继承于 istream 和 ostream<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 istream 和 ostream 又继承于 ios<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- a.公有继承(public) 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时<span class=<h-char class=
多态<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 多态是指通过基类的指针或者引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在运行时动态调用实际绑定对象函数的行为<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 与之相对应的编译时绑定函数称为静态绑定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 多态是设计模式的基础<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 多态是框架的基础<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 C++静态多态与动态多态
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 构造函数和析构函数的执行顺序<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
构造函数<span class=<h-char class=
- 首先调用父类的构造函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 调用成员变量的构造函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 调用类自身的构造函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
析构函数 对于栈对象或者全局对象<span class=<h-char class=
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 虚函数是怎么实现的
每一个含有虚函数的类都至少有有一个与之对应的虚函数表<span class=<h-char class=
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 构造函数为什么一般不定义为虚函数<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 而析构函数一般写成虚函数的原因 <span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- 构造函数不能声明为虚函数 1). 因为创建一个对象时需要确定对象的类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而虚函数是在运行时确定其类型的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而在构造一个对象时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 由于对象还未创建成功<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 编译器无法知道对象的实际类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 是类本身还是类的派生类等等 2). 虚函数的调用需要虚函数表指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而该指针存放在对象的内存空间中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 若构造函数声明为虚函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么由于对象还未创建<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 还没有内存空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 更没有虚函数表地址用来调用虚函数即构造函数了 - 析构函数最好声明为虚函数 首先析构函数可以为虚函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当析构一个指向派生类的基类指针时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 最好将基类的析构函数声明为虚函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 否则可以存在内存泄露的问题<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如果析构函数不被声明成虚函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则编译器实施静态绑定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在删除指向派生类的基类指针时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只会调用基类的析构函数而不调用派生类析构函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这样就会造成派生类对象析构不完全<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 子类析构时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 要调用父类的析构函数吗<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ? 析构函数调用的次序时先派生类后基类的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 和构造函数的执行顺序相反<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 并且析构函数要是virtual的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 否则如果用父类的指针指向子类对象的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 析构函数静态绑定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不会调用子类的析构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 不用显式调用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会自动调用
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 细看拷贝构造函数
对于 class A<span class=<h-char class=
|
- 为什么必须是当前类的引用呢<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ? 循环调用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如果拷贝构造函数的参数不是当前类的引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而是当前类的对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么在调用拷贝构造函数时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会将另外一个对象直接传递给形参<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这本身就是一次拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会再次调用拷贝构造函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后又将一个对象直接传递给了形参<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 将继续调用拷贝构造函数……这个过程会一直持续下去<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 没有尽头<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 陷入死循环<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
只有当参数是当前类的引用时<span class=<h-char class=
- 为什么是 const 引用呢<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ? 拷贝构造函数的目的是用其它对象的数据来初始化当前对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并没有期望更改其它对象的数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 添加 const 限制后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这个含义更加明确了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
另外一个原因是<span class=<h-char class=
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 静态绑定和动态绑定的介绍
静态绑定和动态绑定是C++多态性的一种特性
- 对象的静态类型和动态类型 由于继承导致对象的指针和引用具有两种不同的类型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 静态类型和动态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 静态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 对象在声明时采用的类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在编译时确定 动态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 当前对象所指的类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在运行期决定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对象的动态类型可变<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 静态类型无法更改 - 静态绑定和动态绑定 静态绑定<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 绑定的是对象的静态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 函数依赖于对象的静态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在编译期确定 动态绑定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 绑定的是对象的动态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 函数依赖于对象的动态类型<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在运行期确定 只有虚函数才使用的是动态绑定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其他的全部是静态绑定 - 引用是否能实现动态绑定<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 为什么引用可以实现 可以<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 因为引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 或指针<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 既可以指向基类对象也可以指向派生类对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这一事实是动态绑定的关键<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 用引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 或指针<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 调用的虚函数在运行时确定<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被调用的函数是引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 或指针<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 所指的对象的实际类型所定义的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
8<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 深拷贝和浅拷贝的区别
深拷贝和浅拷贝可以简单的理解为<span class=<h-char class=
9<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么情况下会调用拷贝构造函数<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 三种情况<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >)
系统自动生成的构造函数<span class=<h-char class=
- 用类的一个对象去初始化另一个对象的时候
- 当函数的参数是类的对象时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就是值传递的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果是引用传递则不会调用 - 当函数的返回值是类的对象或者引用的时候
10<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 类对象的大小受哪些因素影响<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- 类的非静态成员变量大小<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 静态成员不占据类的空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 成员函数也不占据类的空间大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 内存对齐另外分配的空间大小<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 类内的数据也是需要进行内存对齐操作的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 虚函数的话<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会在类对象插入vptr指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 加上指针大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 当该该类是某类的派生类<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么派生类继承的基类部分的数据成员也会存在在派生类中的空间中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 也会对派生类进行扩展<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
11<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 拷贝构造函数和赋值运算符的理解
- 拷贝构造函数生成新的类对象<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而赋值运算符不能<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 由于拷贝构造函数是直接构造一个新的类对象<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以在初始化这个对象之前不用检验源对象 是否和新建对象相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而赋值运算符则需要这个操作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
注 <span class=<h-char class=
12<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++空类默认有哪些成员函数<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
答<span class=<h-char class=
13<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 如果虚函数是有效的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 那为什么不把所有函数设为虚函数<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
答<span class=<h-char class=
14<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 构造函数和虚构函数可以是内联函数<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
构造函数<span class=<h-char class=
15<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 虚函数声明为inline
inline是编译期决定的<span class=<h-char class=
16<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++的空类有哪些成员函数
- 缺省构造函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 缺省拷贝构造函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 缺省析构函数<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 缺省赋值运算符<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 缺省取址运算符<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 缺省取址运算符 const<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
注意<span class=<h-char class=
17<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++中的五种构造函数
- 默认构造函数
- 普通构造函数
- 拷贝构造函数
- 转换构造函数
- 移动构造函数 详见<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : C++中的五种构造函数
第三部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 c++11/c++14/c++17
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++11 中有哪些智能指针<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? shared_ptr 的引用计数是如何实现的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? unique_ptr 的unique 是如何实现的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? make_shared 和 make_unique 的作用<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 智能指针使用注意事项<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
C++ 11 中的智能指针有<span class=<h-char class=
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 智能指针weak_ptr 能够破坏环型引用的原理<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 引用计数的原理<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >)
weak_ptr只是提供了对管理对象的一个访问手段<span class=<h-char class=
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++ 的闭包
闭包<span class=<h-char class=
引用百度上对闭包的定义<span class=<h-char class=
bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ : 闭包是指可以包含自由<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ > “ 未绑定到特定对象<span class=<h-char class= ( bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ ) 变量的代码块<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ ; 这些变量不是在这个代码块内或者任何全局上下文中定义的<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ , 而是在定义代码块的环境中定义<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ > “ 局部变量<span class=<h-char class= ( bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ ) <h-char class=bd bd-beg “ > “ 。 “闭包” 一词来源于以下两者的结合<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ : 要执行的代码块<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ > “ 由于自由变量被包含在代码块中<span class=<h-char class= ( bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ , 这些自由变量以及它们引用的对象没有被释放<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ ) 和为自由变量提供绑定的计算环境<span class=<h-char class=bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ > “ 作用域<span class=<h-char class= ( bd bd-beg “ > “ bd-box<h-char class= “ bd bd-beg “ > “ ><h-char class= “ bd bd-beg “ > “ ) <h-char class=bd bd-beg “ > “ 。
详见<span class=<h-char class=
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 lambda 表达式<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 怎么捕获外部变量
- 值捕获: 值捕获和参数传递中的值传递类似<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被捕获的变量的值在Lambda表达式创建时通过值拷贝的方式传入<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因此随后对该变量的修改不会影响影响Lambda表达式中的值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 引用捕获: 使用引用捕获一个外部变量<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只需要在捕获列表变量前面加上一个引用说明符&<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 隐式捕获: 还可以让编译器根据函数体中的代码来推断需要捕获哪些变量<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这种方式称之为隐式捕获 - 混合方式捕获: 即同时使用显式捕获和隐式捕获<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 混合捕获时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 捕获列表中的第一个元素必须是 = 或 &<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 此符号指定了默认捕获的方式是值捕获或引用捕获<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
C++11捕获外部变量总结
| 捕获形式 | 说明 |
|---|---|
| [] | 不捕获任何外部变量 |
| [变量名, …] | 默认以值得形式捕获指定的多个外部变量<span class=<h-char class= |
| [this] | 以值的形式捕获this指针 |
| [=] | 以值的形式捕获所有外部变量 |
| [&] | 以引用形式捕获所有外部变量 |
| [=, &x] | 变量x以引用形式捕获<span class=<h-char class= |
| [&, x] | 变量x以值的形式捕获<span class=<h-char class= |
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++ 的垃圾回收机制
很多语言都有对内存自动管理<span class=<h-char class=
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 vector的clear()的时间复杂度是多少<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
C++标准明确指出不管是序列容器<span class=<h-char class=
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++11为什么引入enum class<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- C++98 的 enum 是“非域化的”<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 而 C++11 的 enum class 是“域化的”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 限制了枚举成员只在域内可见 - enum class 的缺省潜在类型 (underlying type) 是 int 型<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 enum 没有缺省潜在类型 - enum class 一般总是前置声明<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而 enum 只有在指定了潜在类型时才可以是前置声明
详见<span class=<h-char class=
8<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 std::thread使用lambda做回调<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 有没有什么注意事项<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
- 使用到外部引用要小心谨慎<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 避免悬空引用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 若需要用到的外部局部变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需以值传递的方式捕获而非引用捕获<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 若是外部指针变量则需深拷贝<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 - 谨慎使用或者不用外部指针<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如果你用值捕获了个指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 你在lambda创建的闭包中持有这个指针的拷贝<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但你不能阻止lambda外面的代码删除指针指向的内容<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 从而导致你拷贝的指针空悬<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 注意引用捕获陷阱<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 引用捕获[&]不要使用外部局部变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 注意this陷阱<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : lambda里避免有全局变量或静态变量或者比当前类生命周期更长的变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 Effective Modern C++ 条款31 对于lambda表达式<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 避免使用默认捕获模式<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 避免使用默认捕获模式(<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 即“[=]”或“[&]”,它可能导致你看不出悬空引用问题)<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 默认值捕获就意外地捕获了this指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而不是你以为的外部变量<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
例子参考<span class=<h-char class=
9<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++11的thread_local有没有使用过<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
有且只有thread_local关键字修饰的变量具有线程周期(thread duration)<span class=<h-char class=
- 命名空间下的全局变量
- 类的static成员变量
- 本地变量
详见<span class=<h-char class=
10<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 谈一谈你对zero overhead<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 零开销原则<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) 的理解
- 不需要为没有使用到的语言特性付出代价<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 使用某种语言特性<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不会带来运行时的代价<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
详见<span class=<h-char class=
11<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 了解移动语义和完美转发吗<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
移动语义<span class=<h-char class=
完美转发<span class=<h-char class=
12<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 了解列表初始化吗<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
列表初始化<span class=<h-char class=
第四部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 多线程<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 多进程<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >) 相关
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 线程与进程的区别
线程与进程的比较如下<span class=<h-char class=
- 进程是资源<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 包括内存<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 打开的文件等<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 分配的单位<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 线程是 CPU 调度的单位<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 进程拥有一个完整的资源平台<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而线程只独享必不可少的资源<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如寄存器和栈<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 线程同样具有就绪<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 阻塞<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 执行三种基本状态<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 同样具有状态之间的转换关系<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 线程能减少并发执行的时间和空间开销<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ;
对于<span class=<h-char class=
- 线程的创建时间比进程快<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为进程在创建的过程中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 还需要资源管理信息<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 比如内存管理信息<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 文件管理信息<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而线程在创建的过程中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不会涉及这些资源管理信息<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而是共享它们<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 线程的终止时间比进程快<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为线程释放的资源相比进程少很多<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 同一个进程内的线程切换比进程切换快<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为线程具有相同的地址空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 虚拟内存共享<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 这意味着同一个进程的线程都具有同一个页表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么在切换的时候不需要切换页表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 而对于进程之间的切换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 切换的时候要把页表给切换掉<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而页表的切换过程开销是比较大的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 由于同一进程的各线程间共享内存和文件资源<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么在线程之间数据传递的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就不需要经过内核了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 这就使得线程之间的数据交互效率更高了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 所以<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 线程比进程不管是时间效率<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 还是空间效率都要高<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
进程之间私有和共享的资源 私有<span class=<h-char class=
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么是线程不安全?
在随机调度之下,线程执行有多种可能,其中某些可能会导致代码出bug就称为线程不安全.
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 造成线程不安全的原因
- 操作系统的随机调度/抢占式执行(万恶之源)–>无法改变
- 多个线程修改同一个变量(一个字都不能少)—>尽量避免
- 有些修改操作,不是原子的!(不可拆分的最小单位,就叫原子 即对应一条机器指令)—>通过加锁操作,把指令打包
- 内存可见性问题(内存改了,但是在优化的背景下,读不到,看不见) 如:线程1一直在读取硬盘上的资源再判断,在多次读取硬盘并获得相同的结果后编译器会认为这样的做法过于低效,然后就会省略读取的过程,一直判断,若此时有线程2需要这个判断结果(读取到数据后的判断结果)就会出现问题.
- 指令重排序(也是编译器,操作系统等的优化,调整了代码的执行顺序)
最常见的就是对象new的问题<span class=<h-char class=
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++线程中的几类锁
线程之间的锁有<span class=<h-char class=
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么是死锁<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 解决方式
死锁<span class=<h-char class=
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 进程之间的通信方式
管道<span class=<h-char class=
信号量<span class=<h-char class=
信号<span class=<h-char class=
消息队列<span class=<h-char class=
共享内存<span class=<h-char class=
套接字<span class=<h-char class=
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 线程之间的通信方式
锁机制 包括互斥锁/量<span class=<h-char class=
- 互斥锁/量<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ mutex<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 提供了以排他方式防止数据结构被并发修改的方法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 读写锁<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ reader-writer lock<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 允许多个线程同时读共享数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而对写操作是互斥的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 自旋锁<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ spin lock<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 与互斥锁类似<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 都是为了保护共享资源<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 互斥锁是当资源被占用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 申请者进入睡眠状态<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 而自旋锁则循环检测保持者是否已经释放锁<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 条件变量<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ condition<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 可以以原子的方式阻塞进程<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 直到某个特定条件为真为止<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 对条件的测试是在互斥锁的保护下进行的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 条件变量始终与互斥锁一起使用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
信号量机制(Semaphore)
- 无名线程信号量
- 命名线程信号量 信号机制(Signal)<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 类似进程间的信号处理 屏障<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ barrier<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ : 屏障允许每个线程等待<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 直到所有的合作线程都达到某一点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后从该点继续执行<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 线程间的通信目的主要是用于线程同步<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以线程没有像进程通信中的用于数据交换的通信机制
第五部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL 六大组件
STL 六大组件<span class=<h-char class=
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 stack 中有 pop() 和 top() 方法<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 为什么不直接用 pop() 实现弹出和取值的功能<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
把pop()和top()的功能放在一个函数中<span class=<h-char class=
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL库用过吗<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 常见的STL容器有哪些<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 算法用过几个<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
STL包括两部分内容<span class=<h-char class=
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL中map <span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 set<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 multiset<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 multimap的底层原理<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >( 关联式容器<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >)
map <span class=<h-char class=
- 每个结点或是红色或是黑色<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 根结点是黑色<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 每个叶结点是黑的<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 如果一个结点是红的<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则它的两个儿子均是黑色<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 每个结点到其子孙结点的所有路径上包含相同数目的黑色结点<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 map <span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 set<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 multiset<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 multimap的特点
- set和multiset会根据特定的排序准则自动将元素排序<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , set中元素不允许重复<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , multiset可以重复<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - map和multimap将key和value组成的pair作为元素<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 根据key的排序准则自动将元素排序<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 因为红黑树也是二叉搜索树<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以map默认是按key排序的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , map中元素的key不允许重复<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , multimap可以重复<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - map和set的增删改查速度为都是logn<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 是比较高效的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 hash_map与map的区别<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >? 什么时候用hash_map<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 什么时候用map<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
构造函数<span class=<h-char class=
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL中unordered_map和map的区别
map是STL中的一个关联容器<span class=<h-char class=
8<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL中的vector的实现<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 是怎么扩容的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
vector使用的注意点及其原因<span class=<h-char class=
9<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 C++中vector和list的区别
vector和数组类似<span class=<h-char class=
10<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL内存优化<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
STL内存管理使用二级内存配置器<span class=<h-char class=
- 第一级配置器<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 第一级配置器以malloc()<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , free()<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , realloc()等C函数执行实际的内存配置<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 重新配置等操作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并且能在内存需求不被满足的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 调用一个指定的函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 一级空间配置器分配的是大于128字节的空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果分配不成功<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 调用句柄释放一部分内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果还不能分配成功<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 抛出异常<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 第一级配置器只是对malloc函数和free函数的简单封装<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在allocate内调用malloc<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 在deallocate内调用free<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 同时第一级配置器的oom_malloc函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 用来处理malloc失败的情况<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 第二级配置器<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 第一级配置器直接调用malloc和free带来了几个问题<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 内存分配/释放的效率低 当配置大量的小内存块时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会导致内存碎片比较严重 配置内存时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需要额外的部分空间存储内存块信息<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以配置大量的小内存块时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 还会导致额外内存负担 如果分配的区块小于128bytes<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则以内存池管理<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 第二级配置器维护了一个自由链表数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 每次需要分配内存时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 直接从相应的链表上取出一个内存节点就完成工作<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 效率很高<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 自由链表数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 自由链表数组其实就是个指针数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 数组中的每个指针元素指向一个链表的起始节点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 数组大小为16<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 即维护了16个链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 链表的每个节点就是实际的内存块<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 相同链表上的内存块大小都相同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不同链表的内存块大小不同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 从8一直到128<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 如下所示<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , obj为链表上的节点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , free_list就是链表数组<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 内存分配<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : allocate函数内先判断要分配的内存大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 若大于128字节<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 直接调用第一级配置器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 否则根据要分配的内存大小从16个链表中选出一个链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 取出该链表的第一个节点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 若相应的链表为空<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则调用refill函数填充该链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 默认是取出20个数据块<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 填充链表 refill<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 若allocate函数内要取出节点的链表为空<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则会调用refill函数填充该链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 refill函数内会先调用chunk_alloc函数从内存池分配一大块内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 该内存大小默认为20个链表节点大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当内存池的内存也不足时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 返回的内存块节点数目会不足20个<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 接着refill的工作就是将这一大块内存分成20份相同大小的内存块<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并将各内存块连接起来形成一个链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 内存池<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : chunk_alloc函数内管理了一块内存池<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当refill函数要填充链表时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 就会调用chunk_alloc函数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 从内存池取出相应的内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 在chunk_alloc函数内首先判断内存池大小是否足够填充一个有20个节点的链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 若内存池足够大<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则直接返回20个内存节点大小的内存块给refill<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 若内存池大小无法满足20个内存节点的大小<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但至少满足1个内存节点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则直接返回相应的内存节点大小的内存块给refill<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 若内存池连1个内存节点大小的内存块都无法提供<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则chunk_alloc函数会将内存池中那一点点的内存大小分配给其他合适的链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后去调用malloc函数分配的内存大小为所需的两倍<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 若malloc成功<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则返回相应的内存大小给refill<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 若malloc失败<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会先搜寻其他链表的可用的内存块<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 添加到内存池<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 然后递归调用chunk_alloc函数来分配内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 若其他链表也无内存块可用<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则只能调用第一级空间配置器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
11<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 正确释放vector的内存(clear(), swap(), shrink_to_fit())
vec.clear()<span class=<h-char class=
12<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 什么情况下用vector<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 什么情况下用list<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 什么情况下用deque
- vector可以随机存储元素<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 即可以通过公式直接计算出元素地址<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而不需要挨个查找<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ , 但在非尾部插入删除数据时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 效率很低<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 适合对象简单<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对象数量变化不大<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 随机访问频繁<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 除非必要<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 我们尽可能选择使用vector而非deque<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为deque的迭代器比vector迭代器复杂很多<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - list不支持随机存储<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 适用于对象大<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 对象数量变化频繁<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 插入和删除频繁<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 比如写多读少的场景<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 需要从首尾两端进行插入或删除操作的时候需要选择deque<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
13<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 priority_queue的底层原理
priority_queue<span class=<h-char class=
14<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL线程不安全的情况
- 在对同一个容器进行多线程的读写<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 写操作时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 在每次调用容器的成员函数期间都要锁定该容器<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 在每个容器返回的迭代器<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 例如通过调用begin或end<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 的生存期之内都要锁定该容器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; - 在每个在容器上调用的算法执行期间锁定该容器<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
推荐阅读<span class=<h-char class=
15<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 vector 中迭代器失效的情况
- 当插入<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ push_back<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 一个元素后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , end操作返回的迭代器肯定失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 当插入(push_back)一个元素后<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , capacity返回值与没有插入元素之前相比有改变<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 则需要重新加载整个容器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 此时first和end操作返回的迭代器都会失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 当进行删除操作<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ erase<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , pop_back<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) 后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 指向删除点的迭代器全部失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ; 指向删除点后面的元素的迭代器也将全部失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
16<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 迭代器的几种失效的情况
- vector<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 deque<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 该数据结构分配在连续的内存中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 当删除一个元素后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 内存中的数据会发生移动以保证数据的紧凑<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 所以删除一个元素后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 其他数据的地址发生了变化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 之前获取的迭代器根据原有信息就访问不到正确的数据 解决方法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : erase返回下一个有效迭代器的值 - map<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 set<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 multiset<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 map<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 multimap<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 树形数据结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 以红黑树或者平衡二叉树组织数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 虽然删除了一个元素<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 整棵树也会调整<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 以符合红黑树或者二叉树的规范<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 但是单个节点在内存中的地址没有变化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 变化的是各节点之间的指向关系<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 删除一个结点不会对其他结点造成影响<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 erase迭代器只是被删元素的迭代器失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - list<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 链表型数据结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 双向链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使用不连续分配的内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 删除运算使指向删除位置的迭代器失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不会使其他迭代器失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
17<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 STL 是复制性还是侵入性
STL实现的容器都是非侵入式容器<span class=<h-char class=
18<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 vector使用注意事项
- 在push_back()<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 resize()<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 insert()后有可能引起重新分配内存<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 此时原始的迭代器失效<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 需要重新生成一次迭代器 - 为了防止多次扩容造成性能低<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以先使用reserve()<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 预留足够的空间<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 最后在使用 shrink_to_fit()收缩空间 - vector不能用来存储bool类型的元素<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存储机理不同<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , bool类型的元素存储到vector中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 会转化为1个bit<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不是1个byte<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以用deque或者是bitset存储bool类型的 - vector的扩容<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : VS是1.5倍<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 、 GCC是2倍
第六部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 网络编程
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 三次握手和四次挥手
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 TCP 和 UDP 的区别
- TCP面向连接<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 如打电话要先拨号建立连接<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) ;UDP是无连接的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 即发送数据之前不需要建立连接 - TCP提供可靠的服务<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 也就是说<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 通过TCP连接传送的数据<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 无差错<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不丢失<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不重复<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 且按序到达;UDP尽最大努力交付<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 即不保 证可靠交付 - TCP面向字节流<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因此网络出现拥塞不会使源主机的发送速率降低<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 对实时应用很有用<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如IP电话<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 实时视频会议等<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) - 每一条TCP连接只能是点到点的;UDP支持一对一<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 一对多<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 多对一和多对多的交互通信 - TCP首部开销20字节;UDP的首部开销小<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只有8个字节 - TCP的逻辑通信信道是全双工的可靠信道<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , UDP则是不可靠信道 详见<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : TCP和UDP的最完整的区别
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 TCP 粘包 <span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 拆包
如果应用一次请求发送的数据量比较小<span class=<h-char class=
- 发送端给每个数据包添加包首部<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 发送端将每个数据包封装为固定长度<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 可以在数据包之间设置边界<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 详见<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 一分钟看懂TCP粘包拆包
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 TCP 丢包
服务器给客户端发大量数据<span class=<h-char class=
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 为什么“握手”是三次<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, “挥手”却要四次<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
TCP建立连接时之所以只需要<span class=<h-char class=
- 建立连接时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以直接返回SYN和ACK报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 开始建立连接<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 释放连接时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被动方服务器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 突然收到主动方客户端释放连接的请求时并不能立即释放连接<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为还有必要的数据需要处理<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以服务器先返回ACK确认收到报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 经过CLOSE-WAIT阶段准备好释放连接之后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 才能返回FIN释放连接报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
所以是“三次握手”<span class=<h-char class=
6<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 为什么“握手”是三次<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, “挥手”却要四次<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >?
TCP建立连接时之所以只需要<span class=<h-char class=
- TCP释放连接时之所以需要“四次挥手”,是因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 握手<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 传输的<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 为何建立连接时一起传输<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 释放连接时却要分开传输<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ? 建立连接时<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 可以直接返回SYN和ACK报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 开始建立连接<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 释放连接时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 被动方服务器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 突然收到主动方客户端释放连接的请求时并不能立即释放连接<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 因为还有必要的数据需要处理<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 所以服务器先返回ACK确认收到报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 经过CLOSE-WAIT阶段准备好释放连接之后<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 才能返回FIN释放连接报文<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
所以是“三次握手”<span class=<h-char class=
7<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 网络的七层模型<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 作用<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 传输单位分别是什么
整个模型分为七层<span class=<h-char class=
详见<span class=<h-char class=
第七部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 设计模式
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 设计模式
- 创建型模式 对象实例化的模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 创建型模式用于解耦对象的实例化过程<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 单例模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 某个类智能有一个实例<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 提供一个全局的访问点<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 工厂模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 一个工厂类根据传入的参量决定创建出哪一种产品类的实例<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 抽象工厂模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 创建相关或依赖对象的家族<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而无需明确指定具体类<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 建造者模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 封装一个复杂对象的创建过程<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并可以按步骤构造<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 原型模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 通过复制现有的实例来创建新的实例<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 结构型模式 把类或对象结合在一起形成一个更大的结构<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 装饰器模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 动态的给对象添加新的功能<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 代理模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 为其它对象提供一个代理以便控制这个对象的访问<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 桥接模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将抽象部分和它的实现部分分离<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使它们都可以独立的变化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 适配器模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将一个类的方法接口转换成客户希望的另一个接口<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 组合模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将对象组合成树形结构以表示“部分-整体”的层次结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 外观模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 对外提供一个统一的方法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 来访问子系统中的一群接口<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 享元模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 通过共享技术来有效的支持大量细粒度的对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 行为型模式 类和对象如何交互<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 及划分责任和算法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 策略模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 定义一系列算法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 把他们封装起来<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并且使它们可以相互替换<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 模板模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 定义一个算法结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而将一些步骤延迟到子类实现<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 命令模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将命令请求封装为一个对象<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使得可以用不同的请求来进行参数化<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 迭代器模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 一种遍历访问聚合对象中各个元素的方法<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不暴露该对象的内部结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 观察者模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 对象间的一对多的依赖关系<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 仲裁者模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 用一个中介对象来封装一系列的对象交互<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 备忘录模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 在不破坏封装的前提下<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 保持对象的内部状态<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 解释器模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 给定一个语言<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 定义它的文法的一种表示<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 并定义一个解释器<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 状态模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 允许一个对象在其对象内部状态改变时改变它的行为<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 责任链模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 将请求的发送者和接收者解耦<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 使的多个对象都有处理这个请求的机会<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 - 访问者模式<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 不改变数据结构的前提下<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 增加作用于一组对象元素的新功能<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 单例模式的线程安全问题
饿汉模式的单例模式本身就是现场安全的<span class=<h-char class=
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 工厂方法模式
简单工厂模式 简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式<span class=<h-char class=
- 帮助封装: 实现组件封装<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 面向接口编程 - 解耦合:客户端和具体实现类的解耦合
缺点<span class=<h-char class=
- 可能增加客户端的复杂度
- 不方便扩展子工厂
工厂模式 工厂方法模式同样属于类的创建型模式又被称为多态工厂模式 <span class=<h-char class=
- 需求改变时改动最小
- 具体的创建实例过程与客户端分离
缺点<span class=<h-char class=
- 新增功能时<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 工程量稍大
抽象工厂模式 抽象工厂模式是所有形态的工厂模式中最为抽象和最一般性的<span class=<h-char class=
抽象工厂方法是针对与一个产品族<span class=<h-char class=
- 抽象工厂封装了变化<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 封装了对象创建的具体细节 - 增加新的产品族很方便<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 无须修改已有系统 - 针对接口进行编程而不是针对具体进行编程
缺点<span class=<h-char class=
- 增加新的产品等级结构需对原系统做较大修改(违背开放封闭)
详见<span class=<h-char class=
第八部分<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 数据结构
1<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 双链表和单链表的优缺点
单向链表<span class=<h-char class=
双向链表<span class=<h-char class=
2<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 红黑树比AVL的优势<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 为何用红黑树
红黑树的查询性能略微逊色于AVL树<span class=<h-char class=
3<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 红黑树的高度
从任何一个节点到其最远的后代叶子的节点数不超过到最近的后代叶子的节点数的两倍<span class=<h-char class=
4<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 判断链表是不是环形链表
- 基于循环次数判断的暴力方法
- 如果一个链表不成环<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么它就是可以穷尽的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 我们假定你的链表的节点的个数小于10^4个<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果比这个还多的话<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 也许你需要用到树型结构了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 不然你的速度会比乌龟还慢<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 因此我们可以一直循环<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 循环的时候<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 要么是因为到达了指针的尾部NULL<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 要么是因为循环次数太多超越了节点的个数<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 循环结束时判断循环次数就可以了<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 借助Hash表
- 每次访问节点的时候都判断是否在hash表中<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果没有就加入<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果存在就说明有环<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果没有环<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 一个节点只可能被访问一次,这和我们企图修改链表的数据结构去维护访问次数是等价的<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 只是以一种不影响节点内容的方式去完成<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
- 快慢指针
- 定义两种类型的指针<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , slow慢指针前进步长为1<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 快指针前进步长为2<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ >“ 在第一次前进后要判断前进后是否到达了NULL<span class=<h-char class=( bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ ) <h-char class= bd bd-beg“ >“ 。 这样<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 如果在循环的过程中<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 快指针追上了慢指针<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 那么说明成了环<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。
5<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 简述队列和栈的异同
队列和栈都是线性存储结构<span class=<h-char class=
- 注意<span class=<h-char class=
bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ : 区别栈区和堆区<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 堆区的存取是“顺序随意”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而栈区是“后进先出”<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 栈由编译器自动分配释放 <span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 存放函数的参数值<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 局部变量的值等<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 其操作方式类似于数据结构中的栈<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 堆一般由程序员分配释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 若程序员不释放<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 程序结束时可能由 OS 回收<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 分配方式类似于链表<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 它与本题中的堆和栈是两回事<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ 。 堆栈只是一种数据结构<span class=<h-char class= bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >“ , 而堆区和栈区是程序的不同内存存储区域
整理的原文
参考阅读
万字详解我今年经历的腾讯Linux C++ 笔试/面试题及答案
欢迎指出错误<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >、 遗漏的题<span class=<h-char class=“ bd bd-beg“ >“ bd-box<h-char class=“ bd bd-beg“ >“ ><h-char class=“ bd bd-beg“ >, 尽量做到面试的时候复习一文就够
作者<span class=<h-char class=
链接<span class=<h-char class=
来源<span class=<h-char class=