第二章:标准库简介
(1)复杂度与Big-O:
{
Big-O:将一个算法的运行时间以一个输入量n的函数表示。
}
第三章:C++11新特效
{
3.1.3:一致性初始化:面对任何初始化动作,可以使用相同语法,也就是大括号。如下:
(1)std:initializer_list<> : 支持一系列值进行初始化
3.1.10:C++ lambda表达式总结---匿名函数
(1)lambda表达式与任何函数类似,具有返回类型、参数列表和函数体。与函数不同的是,lambda能定义在函数内部。
格式:[ capture list ] ( parameter list) mutable或exception声明 -> return type { function body } (Lambda表达式可以忽略参数列表和返回类型以及mutable或exception声明)
(0)lambda可以定义在函数内部,使用其局部变量,但它只能使用那些明确指明的变量。lambda通过将外部函数的局部变量包含在其捕获列表中来指出将会使用这些变量
(1)捕获列表(capture list): 处理外部作用于未被传递为参数列表中实参的数据
{
(0)值捕获: 与传值参数类似,采用值捕获的前提是变量可以拷贝。被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝:
{
int v1 = 42;
auto f=[v1]{return v1;};
v1=0;
auto j = f(); //j is 42
由于被捕获变量的值是在lambda创建时拷贝,因此随后对其修改不会影响到lambda内对应的值。
}
(1)引用捕获: 如果我们采用引用方式捕获一个变量,就必须确保被引用的对象在lambda执行的时候是存在的。lambda捕获的都是局部变量,这些变量在函数结束后就不复存在了。
如果lambda可能在函数结束后执行,捕获的引用指向的局部变量已经消失,这就是未定义行为。
{
int v1 = 42;
auto f=[&v1]{return v1;};
v1=0;
auto j = f(); //j is 0
}
(2)隐式捕获:除了显式列出我们希望使用的来自所在函数的变量之外,还可以让编译器根据lambda体中的代码来推断我们要使用哪些变量。为了指示编译器推断捕获列表,
应在捕获列表中写一个” &” 或”=”。 ” &”告诉编译器采用引用捕获方式,”=”则表示采用值捕获方式。
{
void biggies(vector<string> &words, vector<string>::size_ type sz,
ostream &os=cout, char c=' ')
{
//os隐式捕获,引用捕获方式;c显式捕获,值捕获方式
for_each(words.begin(), words.end(),
[&, c](const strinq &s) { os << s << c; });
//os显式捕获,引用捕获方式;c隐式捕获,值捕获方式
for_each(words.begin(), words.end(),
[=, &os](const strinq &s) { os << s << c; });
}
}
当混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个”&”或”=“。此符号指定了默认捕获方式为引用或值;并且显式捕获的变量必须使用与隐式捕获不同的方式。即,如果隐式捕获是引用方式,则显式捕获命名变量必须采用值方式;类似的,如果隐式捕获采用的是值方式,则显式捕获命名变量必须采用引用方式。
}
(2)可变lambda: 对于一个按值捕获的变量,lambda不能改变其值。如果希望能改变这个被捕获的变量的值,就必须在参数列表之后加上关键字mutable(如:[v1] () mutable {return ++v1;)
3.1.11:decltype:它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值
{
(1)基本用法:
int getSize();
int main(void)
{
int tempA = 2;
/*1.dclTempA为int*/
decltype(tempA) dclTempA;
/*2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize,*/
decltype(getSize()) dclTempB;
return 0;
}
(2)总结:decltype和auto都可以用来推断类型,但是二者有几处明显的差异:1.auto忽略顶层const,decltype保留顶层const;2.对引用操作,auto推断出原有类型,decltype推断出引用;3.对解引用操作,auto推断出原有类型,
decltype推断出引用;4.auto推断时会实际执行,decltype不会执行,只做分析。总之在使用中过程中和const、引用和指针结合时需要特别小心。
3.1.15:template:
{
(1)非类型模板参数:bitset
(2)模板参数默认值
(3)typename关键字:用来指明其后是个类型
(4)成员模板:class成员函数可以为template,但是此函数不能为virtual。
}
}
第五章:通用工具
{
(1)pair:将两个value视为一个,主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型
{
(1)#include<utility>
(2)是个结构体,而非class
(3)允许pair<T1, T2> p(p1); //p = p1, p(v1, v2) 等构造函数
(4)make_pair(V1, V2) //返回值为V1,V2的pair,类型通过V1,V2自动推导
{
make_pair用于构建一个pair:
pair make_pair(T1 x, T2 y)
{
return pair(x, y);
}
如:
std::pair m_pairA;
m_pairA = std::make_pair("sn001", 12.5);
std::cout<<m_pairA.first<<" "<<m_pairA.second<<std::endl;
}
(5)方法
{
(1)p.first //或者get(0)(p),返回第一个value; get(0)(p) = X;给第一个元素赋值
(2)p.second //或者get(1)(p),返回第二个value
(3)p == p1 / p != p1 / p > p1 / p < p1 / p >= p1 / p<= p1 //先判断p.first,在判断p.second
(4)p.swap(p1); //或swap(p, p1), 互换p与p1的值
(5)tuple_size<p>::value //返回p中元素个数
(6)tuple_element<N, p>::type //返回p中第N个元素类型
}
}
(2)tuple:不定数值组,可以定义任意多个类型的对象的组合。
{
(1)#include<tuple>
(2)定义
(3)允许tuple<T1, T2…, Tn> t(t1); //t = t1, t(v1, v2,…, Vn) 等构造函数
(4)make_tuple(V1, V2…, Vn) //返回值为V1,V2…Vn的tuple,类型通过V1,V2…Vn自动推导
(5)方法
{
(1)get(0)(t) //返回第一个value; get(0)(t) = X;给第一个元素赋值
(2)t== t/ t!= t1 / t > t1 / t < t1 / t >= t1 / t <= t1 //判断每个元素,且t/t1元素类型必须吻合
(3)t.swap(t1); //或swap(t, t1), 互换t与t1的值
(4)tuple_size<t>::value //返回t中元素个数
(5)tuple_element<N, t>::type //返回t中第N个元素类型
(6)tie<N, t>::type //返回t中第N个元素类型
}
}
(3)智能指针:
{
(1)shared_ptr:是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象.
(1-1)自动释放没有指针引用的资源。(使用引用计数来标识是否有多余指针指向该资源);
(1-2)shared_ptr 对象除了包括一个所拥有对象的指针外, 还必须包括一个引用计数代理对象的指针,因此大小是原始指针的两倍。
{
(1)#include<memory>
(2)std::shared_ptr<Test> p1(new Test); p = p1;
(3)make_shared: 要优于使用new,make_shared可以一次将需要内存分配好
std::shared_ptr<Test> p = std::make_shared<Test>();
(4)auto sp3 = std::make_shared<int>(11);
(4)p.use_count() //返回引用计数个数
(5)p.unique() // 返回是否是独占所有权( use_count 为 1)
(6)p.swap(p1) //
(7)p.reset(new int(33)); //指向新的地址,源对象引用计数减1
(8)指定删除器:智能指针可以指定删除器(默认的deleter是delete p,而不是delete []p,因此用到new T[]时需要重新定义),当智能指针的引用计数为0时,
自动调用指定的删除器来释放内存。std::shared_ptr可以指定删除器的一个原因是其默认删除器不支持数组对象,这一点需要注意。
(9)注意问题
{
(1)不要用一个原始指针初始化多个shared_ptr,原因在于,会造成二次销毁;
{
int *p5 = new int; std::shared_ptr<int> p6(p5); std::shared_ptr<int> p7(p5); // logic error
}
(2)不要在函数实参中创建shared_ptr。因为C++的函数参数的计算顺序在不同的编译器下是不同的。正确的做法是先创建好,然后再传入。
(3)环式指向问题不能释放,两个shared_ptr互相指向会导致他们引用计数始终为1,不能释放
}
}
(2)auto_ptr :是独占的,这是C++98标准下的智能指针; 它的缺点是在转移所有权后会使运行期不安全。
(2-1)不能指向数组,因为auto_ptr在析构的时候只是调用delete,而数组应该要调用delete[]
(2-2)没有使用引用计数,在复制构造函数和赋值构造函数中将对象所有权转移了。
(2-3)不能和标准容器(vector,list,map…)一起使用。
{
(1)#include <memory>
(2)auto_ptr<string> country(new string("USA")); auto_ptr<string> pwin; pwin = country; //将所有权从country[2]转让给pwin,此时country[2]不再引用该字符串从而变成空指针;
(3)
}
(3)weak_ptr: 共享但不拥有,是用来解决shared_ptr的循环引用时出现死锁问题的。是对对象的一种弱引用,它不会增加对象的use_count,weak_ptr和shared_ptr可以相互转化,
shared_ptr可以直接赋值给weak_ptr,weak_ptr也可以通过调用lock函数来获得shared_ptr。
shared_ptr可以通过有效的方法保证智能指针的安全性,但是有时会存在循环引用的问题,建议配合weak_ptr一同使用(注意: weak_ptr是弱指针,他不可以单独使用,必须和shared_ptr一同使用。
{
(1)#include<memory>
(2)
(4)unique_ptr: 是一个独享所有权的智能指针,它提供了严格意义上的所有权
(4-1)是一个独享所有权的智能指针,无法进行复制构造、赋值操作操作,只能进行移动操作。无法使两个unique_ptr指向同一个对象;
(4-2)智能指向一个对象,如果当它指向其他对象时,之前所指向的对象会被摧毁。
(4-3)对象会在它们自身被销毁时使用删除器自动删除它们管理的对象。
(4-4)持创建数组对象方法。扁平化版本
{
(1)#include<memory>
(2)对于new T[]
(3)方法
}
}
(4)第六章数值极值:
{
(1)numeric_limits:模板类,在库编译平台提供基础算术类型的极值等属性信息,取代传统C语言所采用的预处理常数。
{
(1)#include <limits>
(2)numeric_limits<Type>::Fun() //如 numeric_limits<short>::max()
(3)包含:max()/min()/is_signed/lowest()/digits()….
}
(2)Type Trait / Type Utility
{
(1)Type Trait:用来处理类型属性的办法
{
(1)#include<type_traits>
(2)
template <typename T>
void foo(const T& val) {
if (std::is_pointer<T>::value) {
cout << "foo called for a pointer " << endl;
}}
}
}
(3)redio
}
(5)辅助函数
{
}
(6)Clock和Timer
{
(1)chrono:
{
(1)system_clock()/steady_clock()/hign_resolution_clock()
}
(7)头文件cstddef.h/cstdlib.h/cstring.h
{
(1)cstddef.h
(2)cstdlib.h
(3)cstring.h
}
(6)第六章:标准模板库 281
{
(1)容器
{
(1)序列式容器
{
(1)vector:动态数组,
(1-1)若发生了重新分配内存,则原迭代器、指针、引用都会失败。且重新分配比较费时
{
stl::vector<int> vec(5);
(1)#include<vector>
(2)定义:
{
(2-0)
(2-1)reserve():增加了vector的capacity,但是它的size没有改变;是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容
器内的元素。加入新的元素时,要调用push_back()/insert()函数.(避免容器容量不够重新分配空间导致引用、指针、迭代器失效)
(2-2)resize(n) / resize(n, ele):改变了vector的capacity同时也增加了它的size;是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器
内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。
(2-3)shrink_to_fit():降低容量
}
(3)迭代器:
{
(3-1)begin/end():
(3-2)rbegin/rend():
(3-3)cbegin/cend():
(3-4)crbegin/crend():
}
(4)Capacity容量:
{
(4-1)capacity():返回vec容量
(4-2)size():返回元素个数,vec.size() = 5
(4-3)max_size():随机元素最大可能个数,vec.max_size() = 5
(4-4)empty():判断元素是否为空, vec.empty()
(4-5)reserve():扩大vec容量
(4-6)shrink_to_fit:降低容量已符合vec元素个数
}
(5)访问access:可以通过下标
{
(5-1)[ ]:随机访问vec元素,vec[1]
(5-2)at():随机访问vec元素,vec.at(3);只有此进行范围检测
(5-3)front():返回第一个元素, vec.front()
(5-4)back():返回最后一个元素, vec.back()
(5-6)data():返回第一个元素的地址,arr.data()
}
(6)修改Modifiers:
{
(6-1)swap():交换两vector(类型相同,元素个数也相同)的值,不能置换两个vector原迭代器+引用所指向的位置,置换后扔指向原容器,
vec.swap(vec1) / swap(vec, vec1)
(6-2)vec.assign(n, ele):复制n个元素给vec
(6-3)vec.assign(begin, end):复制区间内的元素给vec
(6-4)push_back(ele):在末尾添加一元素,vec.push_back(ele)
(6-5)pop_back():移除末尾元素,但是不返回这个元素,vec.pop_back()
(6-6)insert(pos, ele):在迭代器pos位置之前插入元素,insert(pos, n, ele) / insert(pos, begin, end)….;,并返回新元素位置
(6-7)emplace(pos, V) / emplace_back(V):在pos前或vec末尾插入一个以V为初值的元素,并返回新元素位置
(6-8)erase(pos) / erase(begin, end):移除pos上,或者begin~end之间的元素。
(6-9)clear():移除所有元素,清空容器
}
(7)比较:可以使用>、<、==、!=、>=、<=等符号对两个array数组容器进行比较。
(8)tuple接口:
{
(8-1)获取元素个数:tuple_size<vec>::value
(8-2)获取第N个元素类型:tuple_element<N, vec>::type
(8-3)获取第N个元素值:get<N>(vec)
}
}
(2)deque:动态数组,双端队列;
(2-1)两端都能够进行快速插入或移除元素,vector只能在尾部执行;适合于两端操作场景
{
(1)#include<deque>
(2)定义:
{
}
(3)除了没有capacity、reserve接口,增加了push_front()、pop_front()接口外,其他接口等与vector一样。
}
(3)list:双向链表
{
slt::list<int> lst;
(1)#include<list>
(2)定义
{
}
(3)创建:
{
}
(4)迭代器:
{
(3-1)begin/end():
(3-2)rbegin/rend():
(3-3)cbegin/cend():
(3-4)crbegin/crend():
}
(5)方法:
{
(1)empty():返回容器是否为空
(2)size():返回元素个数
(3)max_size():返回元素个数最大可能性
}
(6)比较:可以使用>、<、==、!=、>=、<=等符号对两个array数组容器进行比较。
(7)访问access:不可以通过下标
{
(1)front():返回第一个元素
(2)back():返回最后一个元素
}
(8)修改Modifiers:
{
(1)执行=号:
(2)assign(n, ele) / assign(begin, end) / assign(初始化列表):赋值
(3)swap(lst, lst1):lst.swap(lst1)置换两个列表
(4)push_back():
(5)pop_back():
(6)push_front():
(7)pop_front():
(8)insert(pos, ele):在迭代器pos位置之前插入元素,insert(pos, n, ele) / insert(pos, begin, end)….;,并返回新元素位置
(9)emplace():
(10)erase(pos) / erase(begin, end):移除pos上,或者begin~end之间的元素。
(11)remove(V):移除所有值为V的元素
(12)remove_if(op):移除所有满足op条件的元素
(13)resize(n) / resize(n, V):扩大到n,并初始化
(14)clear():清除元素
(15)unique():存在相邻且值相等元素,则移除多余只保留一个
(16)unique(op):存在相邻且满足OP条件的元素,则移除多余只保留一个
(17)splice(pos, lst1):将lst1内元素全转移到lst的pos迭代器位置之前
(18)splice(pos, lst1, begin, end):将lst1内begin到end之间的元素全转移到lst的pos迭代器位置之前
(19)sort() / sort(op):以"<" 或 op条件为标准对元素排序
(20)merge(lst1) / merge(lst1, op):将元素lst1转移到lst
(21)reverse():将所有元素反序
}
}
(4)forward_list:单向链表
(4-1)不支持反向迭代器
{
(1)#include<forward_list>
(2)定义:
{
}
(3)
}
(5)array:适用于有固定元素数量的序列;数组类具有固定大小,并且不通过分配器管理其元素的分配,它们是封装固定大小元素数组的聚合类型。
(5-1)序列容器中的元素按严格的线性顺序排序。各个元素按其顺序访问它们的位置。
(5-2)元素存储在连续的存储器位置,允许对元素进行恒定时间随机访问。可以偏移元素的指针以访问其他元素。
(5-3)容器使用隐式构造函数和析构函数静态分配所需的空间。它的大小是编译时常量。没有内存或时间开销。
{
std::array<int, 5> arr = {1, 2, 3, 4, 5};
(1)#include<array>
(2)定义:
(3)迭代器:
{
(3-1)begin/end():
(3-2)rbegin/rend():
(3-3)cbegin/cend():
(3-4)crbegin/crend():
}
(4)Capacity容量:array数组容器的大小是固定的。
{
(4-1)sizeof():返回arr总大小,sizeof(arr) = 20
(4-2)size():返回元素个数,arr.size() = 5
(4-3)max_size():随机元素最大可能个数,arr.max_size() = 5
(4-4)empty():判断元素是否为空, arr.empty()
}
(5)访问access:可以通过下标
{
(5-1)[ ]:随机访问arr元素,arr[1]
(5-2)at():随机访问arr元素,arr.at(3)
(5-3)front():返回第一个元素, arr.front()
(5-4)back():返回最后一个元素, arr.back()
(5-5)data():返回第一个元素的地址,arr.data()
}
(6)修改Modifiers:
{
(6-1)fill():使用X一次性初始化所有元素,arr.fill(X)
(6-2)swap():交换两array(类型相同,元素个数也相同)的值,不能置换两个array原迭代器+引用所指向的位置,置换后扔指向原容器,
arr.swap(arr1) / swap(arr, arr1)
(6-2-1)move():
(6-3)arr = arr1:
}
(7)比较:可以使用>、<、==、!=、>=、<=等符号对两个array数组容器进行比较。
(8)tuple接口:
{
(8-1)获取元素个数:tuple_size<arr>::value
(8-2)获取第N个元素类型:tuple_element<N, arr>::type
(8-3)获取第N个元素值:get<N>(arr)
}
}
(2)关联容器:
{
(1)set / multiset:会根据内部排序准则自动对元素进行排序,两者不同之处为multiset允许元素重复;默认排序准则为“<。
(1-1)不提供任何直接访问元素的函数
(1-2)通过迭代器进行元素间接访问
{
(1)#include<set>
(2)定义:
{
}
(3)迭代器:
{
(3-1)begin/end():
(3-2)rbegin/rend():
(3-3)cbegin/cend():
(3-4)crbegin/crend():
}
(4)方法:
{
(1)key_comp():返回比较准则
(2)value_comp():返回针对值的比较准则(与1相同)
(3)empty():判空
(4)size():返回元素个数
(5)max_size():
}
(5)比较:可以使用>、<、==、!=、>=、<=等符号对两个set进行比较。
(6)查询:
{
(1)count(V):返回值为V的元素个数
(2)find(V):返回值为V的元素,找不到直接返回end()
(3)lower_bound(V):返回“元素值>=V”的第一个位置
(4)upper_bound(V):返回“V>元素值”的第一个位置
(5)equal_bound(V):
}
(7)赋值
{
(1)=号:
(2)swap():st.swap(st1) / swap(st, st1)
(3)insert(V):插入元素,insert(pos, V) / insert(begin, end) / insert({V1, V2, V3….})….;,并返回新元素位置
(4)emplace():
(5)erase(V):移除值等于V的所有元素;erase(begin, end)
(6)clear():清除所有元素
}
}
(3)map / multimap:将key-value当做元素进行管理;以Key为排序准则进行排序
{
(1)#include<map>
(2)定义:
{
}
(3)
{
(3-1)begin/end():
(3-2)rbegin/rend():
(3-3)cbegin/cend():
(3-4)crbegin/crend():
}
(4)方法:
{
(1)key_comp():返回比较准则
(2)value_comp():返回针对值的比较准则(与1相同)
(3)empty():判空
(4)size():返回元素个数
(5)max_size():
}
(5)比较:可以使用>、<、==、!=、>=、<=等符号对两个set进行比较。
(6)查询:
{
(1)count(V):返回Key值为V的元素个数
(2)find(V):返回Key值为V的元素,找不到直接返回end()
(3)lower_bound(V):返回Key值“元素值>=V”的第一个位置
(4)upper_bound(V):返回Key值“V>元素值”的第一个位置
(5)equal_bound(V):区间
}
(7)赋值
{
(1)=号:
(2)swap():mp.swap(mp1) / swap(mp, mp1)
(3)insert(V):插入元素,insert(pos, V) / insert(begin, end) / insert({V1, V2, V3….})….;,并返回新元素位置
(4)emplace():
(5)erase(V) :移除值等于V的所有元素;erase(begin, end) / erase(pos)
(6)clear():清除所有元素
}
(8)访问:
{
}
}
}
}
(3)无序容器:内部不排序
{
(1)unondered_set:
{
(1)#include<unondered_set>
}
(2)unondered_multiset:
{
(1)#include<unondered_set>
}
(3)unondered_map:
{
(1)#include<unondered_map>
}
(4)unondered_multimap:
{
(1)#include<unondered_map>
}
}
(4)特殊容器
{
(1)stack(堆栈):
{
#include<stack>
(1)stack<Type> st;
(2)后进先出
(3)接口
{
(1)push():插入X,st.push(X)
(2)pop():移除元素,st.pop()
(3)top():返回下一个元素
}
}
(2)queue(队列):
{
#include<queue>
(1)queue<Type> qu;
(2)
(3)接口:
{
(1)push():将X放入队列,qu.push(X)
(2)front():放回第一个元素
(3)back():返回最后一个
(4)pop():移除元素,
}
}
(3)priority queue(带优先级的队列):
{
}
(4)
}
(5)string:存在于std中
{
(1)#include<string>
(2)构造函数+迭代器:
{
//迭代器
}
(3)data / c_str / copy
{
}
(4)size / length / max_size / capacity / reserve / shrink_to_fit
{
}
(5)访问:[] / at / front() / back()
{
}
(6)比较:>/</>=……/ compare
{
Str.compare("XXX") //返回0:相等, 大于0:大于, 小于0:小于
}
(7)赋值:= 、assign
{
}
(8)交换:swap
(9)清空
{
}
(10)安插+移除:insert / remove / replace / erase / += / append / push_back
{
}
(11)子字符串+结合:substr / +
{
}
(12)查找
{
}
(13)npos:
{
}
(14)数值转换
{
}
}
getline:
{
}
}
}
}
(2)容器适配器
{
(1)stack:
{
}
(2)queue:
{
}
(3)priority queue:
{
}
}
(3)迭代器
{
}
}
第十一章:算法
{
(0)头文件<algorithm>
(1)for_each(begin, end, op):在C++11中被range-based for循环替换(for(auto elem : coll))替代
{
}
(2)非更易性算法:不会改变元素的值
{
(1)cout / count_if:
{
}
(2)find / find_if / find_if_not:
{
}
(3)equal:区间比较
{
}
(4):检查是否排序
{
}
}
(3)更易性算法
{
(1)copy
{
}
(2)move
{
}
(3)transform
{
}
(4)互换元素
{
}
(5)赋值
{
}
(6)
{
复制和替换
}
}
(4)移除性算法
{
(1)remove
{
复制并移除
}
(2)移除重复元素
{
复制并移除
}
}
(5)变序
{
(1)反序
{
}
(2)rotate / rotate_copy:旋转元素
{
}
(3)排序
{
}
(4)合并
{
}
}
(4)
}
第十四章:正则表达式
{
(0)头文件<regex>
(2)使用场景
{
}
(2)regex_match / regex_search:
{
}
(3)次表达式:
{
(1)match_results
}
(4)regex iterator
{
}
(5)replace
{
}
Raw string
}
第十五章:iostream
{
(1)#include <iostream>
{
}
(2)标准io函数
{
}
(3)格式化
{
}
}
第十八章:并发
{
(1)
(2)高级接口:async / futrue / share futrue
{
}
(3)底层接口:thread
{
}
(4)启动线程
{
}
}