C++ 11 新特性
语法糖部分
-
nullptr:代替NULL;原因:NULL和0有时会分不清,用nullptr专门区分空指针和0
-
auto和decltype:自动类型推导 ;auto可以推导变量的类型,与C语言中原有的auto功能不相同;auto声明的变量必须初始化;auto不能声明为返回值、不能作形参、不能被修饰为模板参数;auto对运行效率没有影响,因为变量类型的推导在编译时本来也要进行;decltype可以分析表达式的类型,但是不计算表达式的值,是对auto只能判断变量类型的补充
-
for循环,支持类似C#的foreach:支持遍历数组、容器、string以及由begin和end定义的序列
-
初始化列表:构造函数的初始化列表。构造函数的执行分为初始化阶段(初始化所有类成员)和计算阶段(构造函数体内的赋值操作),使用初始化列表不需要调用默认构造函数;常量成员、引用类型、没有默认构造函数的类必须使用初始化列表;初始化成员变量的顺序是类中定义的顺序,而不是初始化列表中的顺序
-
lamda表达式,是匿名函数,构成 [捕获区] (参数区) {代码区};捕获区的定义 (a复制a、&b引用b、this当前对象、&以引用捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在;= 以复制捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在;应用场景为sort等自定义比较函数、创建线程thread
右值引用
- 左值:指向稳定的内存空间 Location Value
- 右值:指向临时的内存空间 Read Value
- 左值引用:使用&,相当于给变量取一个别名
- 右值引用:使用&&,相当于给临时变量取一个别名
- 左值引用只能引用左值,右值引用只能引用右值,常量左值引用可以引用所有(但是只读)
- 目的:消除两个对象交互时不必要的对象拷贝,提升效率;更简明的定义泛型函数
移动语义
- 定义:将资源从一个对象转移到另一个对象;移动语义相当于剪切、拷贝语义相当于复制
- 实现移动语义需要增加移动构造函数和移动复制构造函数
- 拷贝构造的参数是常量左值引用,移动构造函数的参数是右值引用,右值将优先进入移动构造函数;移动构造函数会直接把自己的指针指向别人的对象并把别人的指针修改为空
- 如果想把左值进行移动构造,可以用std::move把左值转换成右值,方便应用移动语义
完美转发
- 完美转发就是一个函数将参数转交给另一个函数,它的左/右值和const/non-const属性不发生改变
- 使用通用引用类型和std::forward可以实现
智能指针
- 防止内存泄漏,用来管理野指针
- shared_ptr 基于引用计数,计数降为0时自动释放
- weak_ptr 只引用,不计数,与shared_ptr配套使用
- unique_ptr 基于独占语义,资源唯一地被unique_ptr占有,离开作用域时析构
虚函数
- 定义:虚函数是基类中用virtual声明的函数;纯虚函数:基类中虚函数没有给出函数体、
- 虚函数指针:指向用户定义的虚函数,每个虚函数都会对应一个虚函数指针
- 虚函数表:虚函数指针会排列在对象的地址首部,组成了一种表状结构,叫虚函数表;虚函数表的结构:基类-只有自己定义的虚函数 一般覆盖继承-继承的虚函数指针会覆盖原有的指针 多重继承-按照继承顺序会有多个表项
- 问题:虚函数的代价-虚函数表、虚函数指针 哪些函数不能是虚函数-构造函数、内联函数、静态函数、友元函数、类外的普通函数 菱形继承问题-使用虚继承 父类的析构函数为什么要是虚函数-B类从A类继承的话,delete对象会调用A类的析构函数,B类析构函数不被调用,造成内存泄漏 构造函数为什么不能是虚函数-虚函数需要通过虚函数表调用,而对象没有实例化的时候找不到虚函数表
相关函数类型
- 构造&析构函数 构造函数在创建类的新对象时执行;析构函数在删除所创建的对象时执行
- 拷贝构造函数 把同一个类的对象作为参数初始化新的对象;申请空间、拷贝值
- 友元函数 定义在类外部,可以访问类的私有和保护成员;友元函数不是成员函数
- 内联函数 inline,编译时替换函数体,用于小函数
- 问题:空类默认添加的东西-构造、拷贝构造、析构、赋值运算符 构造函数执行顺序-父类构造、成员对象构造、子类构造 析构函数执行顺序-子类析构、成员对象析构、父类析构 列表初始化比赋值初始化快-列表是分配空间时初始化,赋值是分配好空间之后 构造函数只有在被需要时才会自动生成-类成员有构造函数、父类含有构造函数、类中有虚函数、虚继承
关键字
static
- 静态数据成员和静态成员函数:是属于类但不属于该类的任何对象的变量和函数
- 静态成员函数没有this指针
- 静态成员的初始化:在类体外进行,必须进行初始化
- 静态成员函数仅能访问静态数据成员和函数(没有this指针)
extern
- 置于变量和函数,表示变量和函数定义在别的文件中
- extern “C”,表示内容按照C语言的规则翻译
const
- 修饰普通成员变量 该变量不可被修改
- 修饰非成员变量 修饰全局变量-内存只读,第一次使用时分配内存 修饰局部变量-存储在栈中,代码块结束时释放
- 修饰指针 左定值,右定向
- 参数传递 值传递-不需要修饰,函数会自己拷贝 指针传递-保证指针不被修改 自定义参数类型-拷贝时会调用构造函数,慢,所以用const+引用传递
- 修饰返回值 对自定义类型,在返回值加const,使之变成右值
- 修饰类成员函数 防止成员函数修改对象的值
- 不能与static同用:const对应每个实例,static静态成员没有this指针,不能实例化
类型转换
- 隐式转换 向0取整
- 显示转换有动态、静态、const、重编译
- static_cast 无条件转换、静态、不进行安全检查
- dynamic_cast 动态、有安全检查
- const_cast 修改const内容的一个方式,只能是引用和指针
- reinterpret_cast 不改变二进制,只重新解释变量
STL
vector
- 封装了数组,具有一定容量,超出会resize重新分配空间(弃用当前空间)
- 使用3个迭代器 _Myfirst第一个元素、_Mylast最后一个元素、_Myend空间的末尾字节
deque
- 双队列 用map数组储存各连续空间的指针,ma不够用时弃用并重新分配
- 迭代器使用四个指针 cur当前元素、first队首、last队尾、node二级指针,指向map中指向当前空间的指针
- 使用两个迭代器start、finish,其中的cur分别指向第一个和最后一个元素,first和last分别指向元素所在连续空间的首部和尾部,node指向元素对应的map指针
set
- 集合,自动去重和排序;二叉搜索树(红黑树),查找快
- 不能修改值,可以查找、插入、删除
map
(key,value)形式,key不可以重复;用红黑树实现
unordered_map
哈希表实现
priority_queue
堆heap实现
stack
vector或者list实现
问题
- 迭代器 一种泛化指针;是一种检查和遍历元素的数据类型,容器都定义了自己的迭代器类型
- STL组成 容器、配接器、空间配置器、迭代器、算法、仿函数
- 不允许遍历的容器(不提供迭代器)queue、stack、heap
- allocator,隐藏容器的内存管理工作;默认的allocator:要分配的内存大于128KB,直接用malloc(一级分配器),小于128KB,在一块已经分配好的内存池中取一块内存交付;内存池:由16个不同大小(8的倍数 8,16,32…128)的空闲列表组成;内存池优点:小对象快速分配,避免碎片生成
- erase和remove erase会真正释放空间,remove只是移到末尾
- 哈希冲突的方式 1.开链法:挂个桶,桶太大转红黑树2.开放地址法:线性探测、二次探测、再哈希(用不同的哈希函数)
- new和malloc区别 new是关键字:分配内存-构造函数-析构函数 malloc是函数,分配一定的空间
- B,B+,B*树 B:平衡多路查找树,关键字递增,左小右大 B+:非叶子结点只保留索引 B*:以B+树为基础,满节点后先向兄弟结点转移
- 堆内存和栈内存的区别 堆-程序员手动,复杂 栈-编译器自动,简单