容器:
//see <a target=_blank href="http://www.cplusplus.com/reference/stl/">http://www.cplusplus.com/reference/stl/</a> // 演示STL容器 #include <assert.h> #include <vector> #include <iostream> #include <iterator> #include <list> #include <ext/slist> #include <deque> #include <set> #include <map> #include <ext/hash_set> #include <ext/hash_map> #include <stack> #include <queue> //用于排序的函数对象 struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; //用于哈希查找的函数对象 struct eqstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } }; //哈希查找 void lookup(const __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, eqstr>& Set, const char* word) { __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, eqstr>::const_iterator it = Set.find(word); std::cout << word << ": " << (it != Set.end() ? "present" : "not present") << std::endl; } //哈希查找 void lookup(const __gnu_cxx::hash_multiset<const char*, __gnu_cxx::hash<const char*>, eqstr>& Set, const char* word) { int n_found = Set.count(word); std::cout << word << ": " << n_found << " " << (n_found == 1 ? "instance" : "instances") << std::endl; } // 使用typedef简化容器的类型名 typedef __gnu_cxx::hash_multimap<const char*, int, __gnu_cxx::hash<const char*>, eqstr> map_type; //哈希查找 void lookup(const map_type& Map, const char* str) { std::cout << str << ": "; std::pair<map_type::const_iterator, map_type::const_iterator> p = Map.equal_range(str); for (map_type::const_iterator i = p.first; i != p.second; ++i) std::cout << (*i).second << " "; std::cout << std::endl; } int main(int argc, const char *argv[]) { { //vector<T, Alloc> //支持随机元素访问的动态数组(序列) std::vector<int> V; V.insert(V.begin(), 3); assert(V.size() == 1 && V.capacity() >= 1 && V[0] == 3); //扩大vector的容量到指定值,除非已经超过指定值 std::cout << "size:" << V.size() << ",capacity:" << V.capacity() << std::endl; V.reserve(3); std::cout << "size:" << V.size() << ",capacity:" << V.capacity() << std::endl; //用构造函数复制vector,容量会自动压缩 std::vector<int> temp(V.begin(), V.end()); std::cout << "Use vector's ctor copy:" << std::endl; std::cout << "size:" << temp.size() << ",capacity:" << temp.capacity() << std::endl; //用swap把序列转移到新的vector,容量不会改变, //而且原来的vector会被修改(交换了内容) std::vector<int> temp_swap; temp_swap.swap(V); std::cout << "Use vector's swap:" << std::endl; std::cout << "temp_swap's size:" << temp_swap.size() << ",capacity:" << temp_swap.capacity() << std::endl; std::cout << "V's size:" << V.size() << ",capacity:" << V.capacity() << std::endl; //把序列复制到vector,通常用于输入流 //用法类似std::copy std::cout << "Please input double array (NaN is EOF):" << std::endl; std::istream_iterator<double> first(std::cin); std::istream_iterator<double> eof; std::vector<double> buf(first, eof); std::cout << "input double numbers are:" << std::endl; std::copy(buf.begin(), buf.end(), std::ostream_iterator<double>(std::cout, "\n")); std::cout << std::flush; } { //list<T, Alloc> //双向链表 std::list<int> L; L.push_back(0); L.push_front(1); L.insert(++L.begin(), 2); std::cout << "list:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; //排序 L.sort(); std::cout << "sorted list:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; //合并 std::list<int> L2; L2.push_back(3); L2.push_back(2); L2.push_back(1); L.merge(L2); std::cout << "merged list:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; //颠倒次序 L.reverse(); std::cout << "reversed list:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } { //slist<T, Alloc> //单向链表 //从begin()插入 __gnu_cxx::slist<int> L; L.push_front(0); L.push_front(1); L.insert_after(L.begin(), 2); std::cout << "slist, insert to begin:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; //从end()插入 __gnu_cxx::slist<int>::iterator back = L.previous(L.end()); back = L.insert_after(back, 3); back = L.insert_after(back, 4); back = L.insert_after(back, 5); std::cout << "slist, insert to end:" << std::endl; std::copy(L.begin(), L.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } { //deque<T, Alloc> //双端队列,类似vector, //支持随机访问和双端插入, //但不支持capacity()和reserve() std::deque<int> Q; Q.push_back(3); Q.push_front(1); Q.insert(Q.begin() + 1, 2); Q[2] = 0; std::cout << "deque:" << std::endl; std::copy(Q.begin(), Q.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } { //set<Key, Compare, Alloc> //集合,不重复的序列,可执行交、并、差集 const int N = 6; const char* a[N] = {"isomer", "ephemeral", "prosaic", "nugatory", "artichoke", "serif"}; const char* b[N] = {"flat", "this", "artichoke", "frigate", "prosaic", "isomer"}; std::set<const char*, ltstr> A(a, a + N); std::set<const char*, ltstr> B(b, b + N); std::set<const char*, ltstr> C; std::cout << "Set A: "; std::copy(A.begin(), A.end(), std::ostream_iterator<const char*>(std::cout, " ")); std::cout << std::endl; std::cout << "Set B: "; std::copy(B.begin(), B.end(), std::ostream_iterator<const char*>(std::cout, " ")); std::cout << std::endl; std::cout << "Union: "; std::set_union(A.begin(), A.end(), B.begin(), B.end(), std::ostream_iterator<const char*>(std::cout, " "), ltstr()); std::cout << std::endl; std::cout << "Intersection: "; std::set_intersection(A.begin(), A.end(), B.begin(), B.end(), std::ostream_iterator<const char*>(std::cout, " "), ltstr()); std::cout << std::endl; std::set_difference(A.begin(), A.end(), B.begin(), B.end(), std::inserter(C, C.begin()), ltstr()); std::cout << "Set C (difference of A and B): "; std::copy(C.begin(), C.end(), std::ostream_iterator<const char*>(std::cout, " ")); std::cout << std::endl; } { //map<Key, Data, Compare, Alloc> //关联数组,映射表,键不可重复 std::map<const char*, int, ltstr> months; months["january"] = 31; months["february"] = 28; months["march"] = 31; months["april"] = 30; months["may"] = 31; months["june"] = 30; months["july"] = 31; months["august"] = 31; months["september"] = 30; months["october"] = 31; months["november"] = 30; months["december"] = 31; std::cout << "june -> " << months["june"] << std::endl; std::map<const char*, int, ltstr>::iterator cur = months.find("june"); std::map<const char*, int, ltstr>::iterator prev = cur; std::map<const char*, int, ltstr>::iterator next = cur; ++next; --prev; std::cout << "Previous (in alphabetical order) is " << (*prev).first << std::endl; std::cout << "Next (in alphabetical order) is " << (*next).first << std::endl; //另一种插入键值对的方法(可以判断是否插入成功) std::map<const char*, int, ltstr> M; std::pair<std::map<const char*, int>::iterator, bool> p = M.insert(std::make_pair("A", 17)); //第二返回值表示插入是否成功 if(p.second) std::cout << "insert pair is " << p.first->first << ", " << p.first->second << std::endl; //<< "pair:" << "," << p.second } { //multiset<Key, Compare, Alloc> //允许元素重复的集合 const int N = 10; int a[N] = {4, 1, 1, 1, 1, 1, 0, 5, 1, 0}; int b[N] = {4, 4, 2, 4, 2, 4, 0, 1, 5, 5}; std::multiset<int> A(a, a + N); std::multiset<int> B(b, b + N); std::multiset<int> C; std::cout << "Set A: "; std::copy(A.begin(), A.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; std::cout << "Set B: "; std::copy(B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; std::cout << "Union: "; std::set_union(A.begin(), A.end(), B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; std::cout << "Intersection: "; std::set_intersection(A.begin(), A.end(), B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; std::set_difference(A.begin(), A.end(), B.begin(), B.end(), std::inserter(C, C.begin())); std::cout << "Set C (difference of A and B): "; std::copy(C.begin(), C.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } { //multimap<Key, Data, Compare, Alloc> //键允许重复的关联数组 std::multimap<const char*, int, ltstr> m; m.insert(std::pair<const char* const, int>("a", 1)); m.insert(std::pair<const char* const, int>("c", 2)); m.insert(std::pair<const char* const, int>("b", 3)); m.insert(std::pair<const char* const, int>("b", 4)); m.insert(std::pair<const char* const, int>("a", 5)); m.insert(std::pair<const char* const, int>("b", 6)); std::cout << "Number of elements with key a: " << m.count("a") << std::endl; std::cout << "Number of elements with key b: " << m.count("b") << std::endl; std::cout << "Number of elements with key c: " << m.count("c") << std::endl; std::cout << "Elements in m: " << std::endl; for (std::multimap<const char*, int, ltstr>::iterator it = m.begin(); it != m.end(); ++it) std::cout << " [" << (*it).first << ", " << (*it).second << "]" << std::endl; } { //hash_set<Key, HashFcn, EqualKey, Alloc> //支持哈希查找的集合,不允许元素重复 __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, eqstr> Set; Set.insert("kiwi"); Set.insert("plum"); Set.insert("apple"); Set.insert("mango"); Set.insert("apricot"); Set.insert("banana"); lookup(Set, "mango"); lookup(Set, "apple"); lookup(Set, "durian"); } { //hash_map<Key, Data, HashFcn, EqualKey, Alloc> //支持哈希查找的关联数组,不允许键重复 __gnu_cxx::hash_map<const char*, int, __gnu_cxx::hash<const char*>, eqstr> months; months["january"] = 31; months["february"] = 28; months["march"] = 31; months["april"] = 30; months["may"] = 31; months["june"] = 30; months["july"] = 31; months["august"] = 31; months["september"] = 30; months["october"] = 31; months["november"] = 30; months["december"] = 31; std::cout << "september -> " << months["september"] << std::endl; std::cout << "april -> " << months["april"] << std::endl; std::cout << "june -> " << months["june"] << std::endl; std::cout << "november -> " << months["november"] << std::endl; } { //hash_multiset<Key, HashFcn, EqualKey, Alloc> //支持哈希查找的集合,允许元素重复 __gnu_cxx::hash_multiset<const char*, __gnu_cxx::hash<const char*>, eqstr> Set; Set.insert("mango"); Set.insert("kiwi"); Set.insert("apple"); Set.insert("kiwi"); Set.insert("mango"); Set.insert("mango"); Set.insert("apricot"); Set.insert("banana"); Set.insert("mango"); lookup(Set, "mango"); lookup(Set, "apple"); lookup(Set, "durian"); } { //hash_multimap<Key, Data, HashFcn, EqualKey, Alloc> //支持哈希查找的集合,允许键重复 map_type M; M.insert(map_type::value_type("H", 1)); M.insert(map_type::value_type("H", 2)); M.insert(map_type::value_type("C", 12)); M.insert(map_type::value_type("C", 13)); M.insert(map_type::value_type("O", 16)); M.insert(map_type::value_type("O", 17)); M.insert(map_type::value_type("O", 18)); M.insert(map_type::value_type("I", 127)); lookup(M, "I"); lookup(M, "O"); lookup(M, "Rn"); } { //stack<T, Sequence> //堆栈,后进先出 std::stack<int> S; S.push(8); S.push(7); S.push(4); assert(S.size() == 3); assert(S.top() == 4); S.pop(); assert(S.top() == 7); S.pop(); assert(S.top() == 8); S.pop(); assert(S.empty()); } { //queue<T, Sequence> //队列,先进先出 std::queue<int> Q; Q.push(8); Q.push(7); Q.push(6); Q.push(2); assert(Q.size() == 4); assert(Q.back() == 2); assert(Q.front() == 8); Q.pop(); assert(Q.front() == 7); Q.pop(); assert(Q.front() == 6); Q.pop(); assert(Q.front() == 2); Q.pop(); assert(Q.empty()); } { //priority_queue<T, Sequence, Compare> //优先队列,最先弹出的是队列中的最大值 std::priority_queue<int> Q; Q.push(1); Q.push(4); Q.push(2); Q.push(8); Q.push(5); Q.push(7); assert(Q.size() == 6); assert(Q.top() == 8); Q.pop(); assert(Q.top() == 7); Q.pop(); assert(Q.top() == 5); Q.pop(); assert(Q.top() == 4); Q.pop(); assert(Q.top() == 2); Q.pop(); assert(Q.top() == 1); Q.pop(); assert(Q.empty()); //让队列中最小元素的先出列 //其中,模板的第二参数表示它的底层实现是std::vector<int> std::priority_queue< int, std::vector<int>, std::greater<int> > Q2; Q2.push(4); Q2.push(2); assert(Q2.top() == 2); Q2.pop(); assert(Q2.top() == 4); } //标准C++允许main不返回,但标准C要求必须返回 return 0; }
自定义分配器:
// 19.4.2 一个用户定义分配器 //演示标准库分配器allocator接口的简单实现 #include <cstddef> #include <vector> #include <iostream> #include <iterator> //class Pool定义一个简单接口的小内存块内存池 //这个内存池一次只能分配恒定大小的小内存块(由构造函数参数指定) class Pool { private: //用于分配和释放内存的链表 //比Chunk的粒度小,多个Link分割一个Chunk //分配前Link的next域用于计算下一个分配位置 //分配后Link只是void*内存块的头部 struct Link { Link *next; }; // 底层内存分配区的分区块 // 一个Pool内有多个依次链接的Chunk //每个Chunk被多个Link分割成更小的内存块 //(但所有Link的排列次序不一定依照其所在Chunk块的排列次序), //但因为内存是连续的,所以在增量分配和全体释放时速度会较快 struct Chunk { //让一个Chunk不超过8K且略小于8K enum { SIZE = 8 * 1024 - 16 }; unsigned char mem[SIZE]; Chunk *next; //next应该不会超过16个字节 }; //多个Chunk前后组成一个链表(好像一个栈) Chunk *chunks; //每次alloc()返回的内存块最大大小, //但不能比sizeof(Link)小,也不能比Chunk::SIZE大 const unsigned int esize; //当前空闲Chunk块内的空闲Link头部 Link *head; //禁用默认的复制构造函数和复制赋值, //所以这里不需要定义方法体 private: Pool(Pool& sz); void operator=(Pool&); private: void grow(); public: Pool(unsigned int n);//指定每次alloc()返回的内存块大小 ~Pool(); void* alloc(); //不需要指定内存块大小(在构造函数中指定) void free(void* b); }; //从head链表的头部取出一个Link //如果空闲Chunk块用完,需要分配新的Chunk块, //然后用Link链表分割这个新的空闲Chunk块。 inline void* Pool::alloc() { if (head == 0) { grow(); } Link *p = head; head = p->next; std::cout << "Pool::alloc(): p == " << p << ", head == " << head << std::endl; return p; } //把要释放的b放回head链表的头部 inline void Pool::free(void* b) { Link* p = static_cast<Link*>(b); p->next = head; std::cout << "Pool::free(): p == " << p << ", head == " << head << std::endl; head = p; } Pool::Pool(unsigned int sz) : esize(sz < sizeof(Link) ? sizeof(Link) : sz) { head = 0; chunks = 0; } Pool::~Pool() { Chunk *n = chunks; while (n) { Chunk *p = n; n = n->next; delete p; } } //增量分配内存 //虽然Link*所在的小内存块是连续的, //但alloc的分配次序不一定是连续的 //(因为free()可能放回旧的内存块) void Pool::grow() { Chunk *n = new Chunk(); n->next = chunks; chunks = n; std::cout << "Pool::grow(): esize == " << esize << std::endl; const int nelem = Chunk::SIZE / esize; unsigned char *start = n->mem; unsigned char *last = &start[(nelem - 1) * esize]; for (unsigned char *p = start; p < last; p += esize) { reinterpret_cast<Link*>(p)->next = reinterpret_cast<Link*>(p + esize); } reinterpret_cast<Link*>(last)->next = 0; //见alloc()的if (head == 0) head = reinterpret_cast<Link*>(start); } //template Pool_alloc把class Pool适配到C++标准库的分配器接口 //不完整,因为有些接口没有实现,而有些接口只实现部分功能 template<class T> class Pool_alloc { private: static Pool mem; //全局,以提高效率 public: typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T *pointer; typedef const T *const_pointer; typedef T &reference; typedef const T&const_reference; Pool_alloc(); T* allocate(size_type n, void*); void deallocate(pointer p, size_type n); }; //构造静态的mem域 //因为Pool只能分配固定大小的小内存块, //而且Pool_alloc没有实现rebind方法 //所以这里指定每次分配的连续内存区都必须是sizeof(T) * 128, //虽然造成浪费,但确保分配的内存是连续的。 //没有超过Chunk块的8K上限,所以是安全的。 template <class T> Pool Pool_alloc<T>::mem(sizeof(T) * 128); template <class T> Pool_alloc<T>::Pool_alloc() { } template<class T> T* Pool_alloc<T>::allocate(size_type n, void* = 0) { if (n <= 128) { void *p = mem.alloc(); std::cout << "allocate : " << n << ", " << p << std::endl; return static_cast<T*>(p); } else { //TODO: std::cout << "allocate : " << n << std::endl; throw "allocate error"; //出错 } } template<class T> void Pool_alloc<T>::deallocate(pointer p, size_type n) { if (n <= 128) { std::cout << "deallocate : " << n << ", " << p << std::endl; mem.free(p); return; } else { //TODO: std::cout << "deallocate : " << n << std::endl; throw "deallocate error"; //出错 } } int main(int argc, const char *argv[]) { { std::vector<int> V1; V1.push_back(1); V1.push_back(2); V1.push_back(3); V1.push_back(4); std::cout << "V1:"<< std::endl; std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } { std::cout << "==================="<< std::endl; try { std::vector< int, Pool_alloc<int> > V2; std::cout << "V2.push_back(1);" << std::endl; V2.push_back(1); std::cout << "V2.push_back(2);" << std::endl; V2.push_back(2); std::cout << "V2.push_back(3);" << std::endl; V2.push_back(3); V2.push_back(4); std::cout << "V2:"<< std::endl; std::copy(V2.begin(), V2.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; } catch (const char *&str) { std::cout << str << std::endl; } } return 0; } /** 运行结果: V1: 1 2 3 4 =================== V2.push_back(1); Pool::grow(): esize == 512 Pool::alloc(): p == 0x3e4d68, head == 0x3e4f68 allocate : 1, 0x3e4d68 V2.push_back(2); Pool::alloc(): p == 0x3e4f68, head == 0x3e5168 allocate : 2, 0x3e4f68 deallocate : 1, 0x3e4d68 Pool::free(): p == 0x3e4d68, head == 0x3e5168 V2.push_back(3); Pool::alloc(): p == 0x3e4d68, head == 0x3e5168 allocate : 4, 0x3e4d68 deallocate : 2, 0x3e4f68 Pool::free(): p == 0x3e4f68, head == 0x3e5168 V2: 1 2 3 4 deallocate : 4, 0x3e4d68 Pool::free(): p == 0x3e4d68, head == 0x3e4f68 */