前言
STL(Standard Template Library)标准模板库
STL大致分为六大模块:容器(container),算法(algorithm),迭代器(iterator),仿函数(functor),配接器(adapter),配置器(allocator)
一、容器
container
你必须要知道所有容器都具有的一个基本特性:
它保存元素采用的是“值”(value)语义,也就是说,容器里存储的是元素的拷贝、副本,而不是引用。
容器操作元素的很大一块成本就是值的拷贝。所以,如果元素比较大,或者非常多,那么操作时的拷贝开销就会很高,性能也就不会太好。
- 尽量为元素实现转移构造和转移赋值函数,在加入容器的时候使用std::move()来“转移”,减少元素复制的成本:
Point p; // 一个拷贝成本很高的对象 v.push_back(p); // 存储对象,拷贝构造,成本很高 v.push_back(std::move(p)); // 定义转移构造后就可以转移存储,降低成本 // 直接使用C++11为容器新增加的emplace操作函数,它可以“就地”构造元素,免去了构造后再拷贝、转移的成本 v.emplace_back(...); // 直接在容器里构造元素,不需要拷贝或者转移
- 容器中存放指针,则必须要自己手动管理元素的生命周期
如果真的有这种需求,可以考虑使用智能指针unique_ptr/shared_ptr,让它们帮你自动管理元素。
1.1 顺序容器
1.1.1 std::vector
初始化
方法一
vector<int> vi;
方法二
vector<int> vi(10,10);//size 10,each value 10
方法三
vector<int> vi(arr,arr+10);//begin,end
插入
方法一 push_back
vector<T> a; T val; a.push_back( val);//在末尾插入一个元素
方法二 insert
v2.insert(v2.begin()+4, L"3"); //在指定位置,例如在第五个元素前插入一个元素 v2.insert(v2.end(), L"3"); //在末尾插入一个元素 v2.insert(v2.begin(), L"3"); //在开头插入一个元素
查找
方法一 迭代器
#include <algorithm> ... vector<int> vec; ... vector<int>::iterator it = find(vec.begin(), vec.end(), value); if (it != vec.end()){ //找到了 }
方法二 数组查找
std::vector <T> a; for (size_t i = 0; i < a.size(); i++) { if(value == a[i];{ //找到了 } }
遍历
方法一 迭代器
std::vector <T> a; std::vector <T>::iterator iVector = a.begin(); while(iVector != a.end()) { std::cout<<" dump "<< (*iVector)<<std::endl; ++iVector; }
方法二 数组
std::vector <T> v1; for (size_t i = 0; i < v1.size(); i++) { T tempNum = v1[i]; }
删除
删除最后一个元素
v1.pop_back(); //删除最后一个元素
删除开头的元素
v1.erase(v2.begin()); //删除开头的元素
删除[begin,end]区间的元素
v1.erase(v1.begin(),v1.end);
删除全部元素
方法一
v1.clear()
方法二
std::vector<T>::iterator iVector = v1.begin(); while(iVector != v1.end()) { delete (*iVector)->p; iVector = v1.erase(iVector); }
方法三
while(pVector->size() != 0) { //pop_back方法无返回值 pVector->pop_back(); //删除操作避免大量移动的方法,如果元素有申请堆栈的内存,不可用此方法 }
push_back 与 emplace_back区别
1.2 线性容器
1.1.3 std::list
初始化
list<int> li(10); list<int> li2(10); list<int> li3(10,1);//size 10,each value 1 int arr2[10] = {}; list<int> li4(arr2,arr2+10);//begin,end
1.3 关联容器
关联容器底层数据结构:unordered_map/set基于hash表,不保证插入顺序;map/set基于红黑树,根据键自动排序
1.2.1 std::map
插入
方法一 数组
//map[key] = value map<int,string> mis; mis[0] = "first"; mis[1] = "second"; mis[2] = "third";
方法二 pair
//make_pair map<int,string> mis2(mis.begin(),mis.end()); mis.insert(pair<int, string>(3, "fourth"));
方法三 make_pair
mapStudent.insert(make_pair(1, "student_one"));
方法四 value_type
//value_type mis.insert(map<int, string>::value_type(3, "fourth")); for (auto& pair : mis){ cout << pair.first << ":" << pair.second.c_str() << endl; }
查找
方法一
std::map<T,V> m1; T key; ... if(m1.find(key) != m1.end){ //找到了 }
删除
删除所有
方法一
cmap.erase(cmap.begin(), cmap.end());
方法二
cmap.clear()
插入
查找
删除
std::multimap
多重映射是允许一个键对应多个附加数据的映射。
1.2.3 std::set
std::multiset
多重集合是允许有重复元素的集合
二、算法
algorithm
算法库
三、迭代器
cpp 迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型
四、仿函数
functor
仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。
五、适配器
adapter
是把一个事物,改造一下接口等等。使得其看起来像一个新的事物。适配器其实是一种应用在STL的设计模式。
六、配置器
allocator
默默完成内存配置与释放,对象构造和析构的工作。