C++ Primer读书笔记梳理系列(二)
第八章 顺序容器
vector对象如何增长的
- 做法
- 将已有的元素移动到新空间中
- 然后添加新元素
- 释放旧的存储空间,一般新空间是旧空间的两倍(有的编译器是1.5倍)
- 注意reserve(内存空间),resize(元素个数)的区别
- 注意capacity和size的区别
string
-
构造方法
1. const char*创建string时,指针指向的数组必须以空字符结尾,拷贝操作遇到空字符停止string(cp, n) s是cp指向的数组中前n个字符的拷贝(此数组至少包含n个字符) string s(s2, pos2) s是string s2从下标pos2开始的字符的拷贝(若pos2>s2.size(),此函数行为未定义) string s(s2, pos2, len2) s是string s2从下标pos2开始的len2个字符的拷贝(若pos2>s2.size(),函数行为未定义;若len2太大,只拷贝剩余元素) const char *cp = "Hello World!!!" //以空字符结束的数组 string s1(cp); //拷贝cp直到遇到空字符;s1 = "Hello World!!!"
-
如果传递给构造函数一个计数值,数组就不需要以空字符结尾
char a[] = {'H', 'i'}; //不是以空字符结尾 string s2(a, 2); //虽然a不是以空字符结尾,但因为构造函数给了计数值,所以可以
-
如果我们未传递计数值且数组也未以空字符结尾,或给定的计数值大于数组大小,则是非法的
string s3(a); //非法 string s4(cp, 100); //非法
-
-
截取字符串substr
-
string操作
函数 含义 s.find(args) 查找s中args第一次出现的位置 s.rfind(args) 查找s中args最后一次出现的位置 s.find_first_of(args) 查找s中args中任意一个字符第一次出现的位置 s.find_last_of(args) 查找s中args中任意一个字符最后一次出现的位置 s.find_first_not_of(args) 查找s中第一个不在args中的字符 s.find_last_not_of(args) 查找s中最后一个不在args中的字符 -
数值转换
- to_string()
- stod(s)//string->double
第十章 泛型算法
lambda
-
定义,表达式表示一个可调用的代码单元,我们可以理解为未命名的内联函数
-
形式:[capture list] (parameter list) -> return type {function body}
捕获列表是lambda表达式所在函数中定义的局部变量
-
lambda表达式不能有默认参数
-
捕获方式
- 值捕获,前提是变量可以被拷贝
- 引用捕获,前提是捕获该变量是存在的(可不可以修改取决于绑定的那个变量是不是const)
- 隐式捕获
-
指定lambda返回类型
- 默认情况下,如果一个lambbda 函数体包含return之外的任何语句,则编译器假定此lambda返回viod;
第十二章 动态内存
不同方式定义的类型变量在内存中的存储位置是不同的
- 静态内存:保存局部static对象、类static数据成员、定义在任何函数之外的变量
- 栈内存:保存定义在函数内的非static对象
- 堆:存储动态分配的对象,当动态对象不再使用时,我们必须显式地销毁它们。
动态内存与智能指针
-
种类
- share_ptr允许多个指针指向同一个对象
- unique_ptr独占所指向的对象,不支持拷贝与赋值(一个即将被销毁的unique_ptr除外),但是可以调用一些函数将所有权从一个unique_ptr(非const)转移给另一个unique_ptr。
- weak_ptr,弱引用,指向share_ptr所管理的对象,但是不改变引用计数
-
智能指针的构造函数是explcit
shared_ptr p1(new int(24)); //我们知道这样是对的,直接初始化 shared_ptr p2 = new int(24); //那这样呢?错了
-
不要混合使用普通指针和智能指针
-
不要使用get初始化另一个智能指针或为智能指针赋值
动态数组
这里主要介绍一下alloctor类
-
new的局限性
- 它将内存分配和对象构造放在一起
- delete将对象的析构和内存的释放放在一起
-
先分配大内存,真正需要时才执行对象的创建操作,使用allocator
-
allocator分配未构造的内存
auto q = p; //q指向最后构造的元素之后的位置 alloc.construct(q++); //*q为空字符串 alloc.construct(q++, 10, 'c'); //*q为cccccccccc alloc.construct(q++, "hi"); //*q为hi cout << *q << endl; //不行,q指向未构造的内存! //我们来销毁刚刚构造的对象 while(q != p) { alloc.destroy(--q); //这个--符号的位置和上面++符号的位置要注意啊 } //当元素被销毁后,我们就可以重新使用这部分内存来保存其他string,也可以将其归还给系统 alloc.deallocate(p, n); //这里我们归还给系统了
-
拷贝和填充未初始化内存的算法
vector<int> vi = {0, 1, 2}; allocator<int> alloc; auto p = alloc.allocate(vi.szie()*2); //分配两倍动态内存空间 auto q = uninitialized_copy(vi.begin(), vi.end(), p); //拷贝vi到堆区 uninitialized_fill_n(q, vi.size(), 24); //剩余元素初始化为24