本文根据源代码分析 C++ STL 之体系结构,而STL正是泛型编程(GP)最成功的作品,所以事实上就是以 STL 为标的深层次地探讨泛型编程 所谓 Generic Programming(GP,泛型编程),就是使用 template(模板)为主要工具来编写程序
视频学习:侯捷老师《C++标准库——体系结构与内核分析》 C++ Standard Library vs. Standard Template Library C++ Standard Library C++ 标准库
Standard Template Library STL, 标准模板库
标准库以 header files 形式呈现 C++ 标准库的 header files 不带副档名(.h),例如 #include <vector> 新式 C header files 不带副档名 .h,例如 #include <cstdio> 旧式 C header filles (带有副档名.h)仍然可用,例如 #include <stdio.h> 新式 headers 内的组件封装于 namespace “std”
1 2 using namespace std; using std::cout;
旧式 headers 内的组件不封装于 namespace “std”
资源网站 CPlusPlus.com
CppReference.com
GCC, the GNU Compiler Collection - GNU Project
Bibliography(书目志) 《 THE C++ STANDARD LIBRARY》(SECOND EDITION) 《 STL源码剖析》(侯捷著)
STL体系结构基础介绍 STL六大部件(Components): 容器(Containers) 分配器(Allocators):容器的背后需要 allocator(分配器)来支撑它对内存的使用,容器有一个默认的分配器 算法(Algorithms) 迭代器(Iterators) 适配器(Adapters) 仿函数(Functors)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <vector> #include <algorithm> #include <functional> #include <iostream> using namespace std;int main () { int ia[ 6 ] = { 27 , 210 , 12 , 47 , 109 , 83 }; vector<int ,allocator<int >> vi (ia,ia+6 ); cout << count_if (vi.begin (), vi.end (), not1 (bind2nd (less <int >(), 40 ))); return 0 ; }
复杂度,Complexity,Big-oh 目前常见的 Big-oh 有下列几种情形: 1.O(1)或O(c):称为常数时间(constant time) 2.O(n):称为线性时间(linear time) 3.O(log2 n):称为次线性时间(sub-linear time) 4.O(n2 ):称为平方时间(quadratic time) 5.O(n3 ):称为立方时间(cubic time) 6.O(2n ):称为指数时间(exponential time) 7.O(nlog2 n):介于线性及二次方成长的中间之行为模式
“前闭后开”区间 [ ) c.begin()指向容器第一个元素,c.end()指向容器最后一个元素的下一个位置,*(c.begin())得到第一个元素,*(c.end())报错
1 2 3 4 5 6 Container<T> c; ... Container<T>::iterator ite = c.begin (); for (; ite != c.end (); ++ite) ...
range-based for statement (since C++11) 1 2 3 for ( decl : coll ) { statement }
1 2 3 for ( int i : { 2 , 3 , 5 , 7 , 9 , 13 , 17 , 19 } ) { std::cout << i << std::endl; }
auto keyword (since C++11) 1 2 3 4 5 6 7 8 9 std::vector<double > vec; ... for ( auto elem : vec ) { std::cout << elem << std::endl; } for ( auto & elem : vec ) { elem *= 3 ; }
1 2 3 4 list<string> c; ... list<string>::iterator ite; ite = ::find (c.begin (), c.end (), target);
1 2 3 4 list<string> c; ... auto ite = ::find (c.begin (), c.end (), target);
容器之分类与各种测试 容器——结构与分类 Sequence Containers(序列式容器) Associative Containers(关联式容器):标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
Unordered Containers(无序容器)属于 Associative Containers
Array、Forward-List、Unordered Containers 为 C++11 新增
以下测试程序之辅助函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 using std::cin;using std::cout;using std::string;long get_a_target_long () { long target=0 ; cout << "target" (0 ~" << RAND_MAX << " ): "; cin >> target; return target; } string get_a_target_string() { long target=0; char buf[10]; cout << " target (0 ~" << RAND_MAX << " ): "; cin >> target; snprintf(buf, 10, " %d", target); return string(buf); } int compareLongs(const void* a, const void* b) { return ( *(long*)a - *(long*)b ); } int compareStrings(const void* a, const void* b) { if ( *(string*)a > *(stirng*)b ) return 1; else if ( *(stirng*)a < *(string*)b ) return -1; else return 0; }
Sequence Containers(序列式容器) 使用容器 array(C++11 新增) 空间固定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <array> #include <iostream> #include <ctime> #include <cstdlib> namespace star01{ void test_array () { cout << "\ntest_array().......... \n" ; array<long ,ASIZE> c; clock_t timeStart = clock (); for (long i=0 ; i< ASIZE; ++i) { c[i] = rand (); } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "array.size()= " << c.size () << endl; cout << "array.front()= " << c.front () << endl; cout << "array.back()= " << c.back () <<endl; cout << "array.data()= " << c.data () <<endl; long target = get_a_target_long (); timeStart = clock (); qsort (c.data (), ASIZE, sizeof (long ), compareLongs); long * pItem = (long *)bsearch (&target, (c.data ()), ASIZE, sizeof (long ), compareLongs); cout << "qsort()+bsearch(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != NULL ) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } }
使用容器 vector 每次存满后扩充当前空间倍数(2倍或者其他) 每次扩充两倍或者其他倍数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <vector> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star02{ void test_vector (long & value) { cout << "\ntest_vector().......... \n" ; vector<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push_back (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "mulli-seconds : " << (clock ()-timeStart) << endl; cout << "vector.size()= " << c.size () << endl; cout << "vecotr.front()= " << c.front () << endl; cout << "vector.back()= " << c.back () << endl; cout << "vector.data()= " << c.data () << endl; cout << "vector.capacity()= " << c.capacity () << endl; string target = get_a_target_string (); { timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } { timeStart = clock (); sort (c.begin (), c.end ()); string* pItem = (string*)bsearch (&target, (c.data ()), c.size (), sizeof (string), compareStrings); cout << "sort()+bsearch(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != NULL ) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } } }
使用容器 list 每次扩充一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <list> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star03{ void test_list (long & value) { cout << "\ntest_list().......... \n" ; list<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push_back (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "list.size()= " << c.size () << endl; cout << "list.max_size()= " << c.max_size () << endl; cout << "list.front()= " << c.front () << endl; cout << "list.back()= " << c.back () << endl; string target = get_a_target_string (); timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; timeStart = clock (); c.sort (); cout << "c.sort(), milli-seconds : " << (clock ()-timeStart) << endl; } }
使用容器 forward_list(C++11 新增) 每次扩充一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <forward_list> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star04{ void test_forward_list (long & value) { cout << "\ntest_forward_list().......... \n" ; forward_list<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push_front (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "forward_list.max_size()= " << c.max_size () << endl; cout << "forward_list.front()= " << c.front () << endl; string target = get_a_target_string (); timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; timeStart = clock (); c.sort (); cout << "c.sort(), milli-seconds : " << (clock ()-timeStart) << endl; } }
使用容器 slist GNU_C 很早之前就有的,非标准,类似于 forward_list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <ext\slist> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star10{ void test_slist (long & value) { cout << "\ntest_slist().......... \n" ; __gnu_cxx::slist<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push_front (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; } }
使用容器 deque deque 表面上连续,实际上分段连续,每一个 buffer 上面连续 到达一个 buffer 末尾后,转向下一个 buffer 头,这一行为由 ++ 实现(操作符重载) 当一个 buffer 存满后,会再申请下一个或前一个 buffer 每次扩充一个 buffer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <deque> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star05{ void test_deque (long & value) { cout << "\ntest_deque().......... \n" ; deque<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push_back (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "deque.size()= " << c.size () << endl; cout << "deque.front()= " << c.front () << endl; cout << "deque.back()= " << c.back () << endl; cout << "deque.max_size()= " << c.max_size () << endl; string target = get_a_target_string (); timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; timeStart = clock (); ::sort (c.begin (), c.end ()); cout << "::sort(), milli-seconds : " << (clock ()-timeStart) << endl; } }
使用容器 stack deque 涵盖了 stack 功能,stack 源代码内部拥有一个 deque,从技术上属于 Container Adapter(容器适配器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <stack> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star17{ void test_stack (long & value) { cout << "\ntest_stack().......... \n" ; stack<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; c.pop (); cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; } }
使用容器 queue deque 涵盖了 queue 功能,queue 源代码内部拥有一个 deque,从技术上属于 Container Adapter(容器适配器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <queue> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star18{ void test_queue (long & value) { cout << "\ntest_queue().......... \n" ; queue<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; c.pop (); cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; } }
使用容器 priority_queue heap 使用少,本身借用其他容器作为底部支撑
Associative Containers(关联式容器) 使用容器 multiset 相比于 set ,可以放重复的元素 标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <set> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star06{ void test_multiset (long & value) { cout << "\ntest_multiset().......... \n" ; multiset<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "multiset.size()= " << c.size () << endl; cout << "multiset.max_size()= " << c.max_size () << endl; string target = get_a_target_string (); { timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } { timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } } }
使用容器 multimap 相比于 map ,可以放重复的元素,一个 key 可以对应多个 value 标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <map> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star07{ void test_multimap (long & value) { cout << "\ntest_multimap().......... \n" ; multimap<long , string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (pair <long ,string>(i,buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "multimap.size()= " << c.size () << endl; cout << "multimap.max_size()= " << c.max_size () << endl; long target = get_a_target_long (); timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, value=" << (*pItem).second << endl; else cout << "not found! " << endl; } }
使用容器 unordered_multiset(C++11新增) 相比于 unordered_set ,可以放重复的元素 底层由 hashtable(哈希表)实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 #include <unordered_set> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star08{ void test_unordered_multiset (long & value) { cout << "\ntest_unordered_multiset().......... \n" ; unordered_multiset<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "unordered_multiset.size()= " << c.size () << endl; cout << "unordered_multiset.max_size()= " << c.max_size () << endl; cout << "unordered_multiset.bucket_count()= " << c.bucket_count () << endl; cout << "unordered_multiset.load_factor()= " << c.load_factor () << endl; cout << "unordered_multiset.max_load_factor()= " << c.max_load_factor () << endl; cout << "unordered_multiset.max_bucket_count()= " << c.max_bucket_count () << endl; for (unsigned i=0 ; i< 20 ; ++i) { cout << "bucket #" << i << " has " << c.bucket_size (i) << " elements.\n" ; } string target = get_a_target_string (); { timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } { timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " <<endl; } } }
使用容器 unordered_multimap(C++11新增) 相比于 unordered_map ,可以放重复的元素,一个 key 可以对应多个 value 底层由 hashtable(哈希表)实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <unordered_map> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star09{ void test_unordered_multimap (long & value) { cout << "\ntest_unordered_multimap().......... \n" ; unordered_multimap<long , string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< vlaue; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (pair <long ,string>(i,buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "unordered_multimap.size()= " << c.size () << endl; cout << "unordered_multimap.max_size()= " << c.max_size () << endl; long target = get_a_target_long (); timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, value=" << (*pItem).second << endl; else cout << "not found! " << endl; } }
使用容器 set 相比于 multiset ,不可以放重复的元素 标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <set> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star13{ void test_set (long & value) { cout << "\ntest_set().......... \n" ; set<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "set.size()= " << c.size () << endl; cout << "set.max_size()= " << c.max_size () << endl; string target = get_a_target_string (); { timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } { timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout MM "not found! " << endl; } } }
使用容器 map 相比于 multimap ,不可以放重复的元素,一个 key 只可以对应一个 value 标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <map> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star14{ void test_map (long & value) { cout << "\ntest_map().......... \n" ; map<long , string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c[i] = string (buf); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "map.size()= " << c.size () << endl; cout << "map.max_size()= " << c.max_size () << endl; long target = get_a_target_long (); timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, value=" << (*pItem).second << endl; else cout << "not found! " << endl; } }
使用容器 unordered_set(C++11新增) 相比于 unordered_multiset ,不可以放重复的元素 底层由 hashtable(哈希表)实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 #include <unordered_set> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> #include <algorithm> namespace star15{ void test_unordered_set (long & value) { cout << "\ntest_unordered_set().......... \n" ; unordered_set<string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c.insert (string (buf)); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "unordered_set.size()= " << c.size () << endl; cout << "unordered_set.max_size()= " << c.max_size () << endl; cout << "unordered_set.bucket_count()= " << c.bucket_count () << endl; cout << "unordered_set.load_factor()= " << c.load_factor () << endl; cout << "unordered_set.max_load_factor()= " << c.max_load_factor () << endl; cout << "unordered_set.max_bucket_count()= " << c.max_bucket_count () << endl; for (unsigned i=0 ; i< 20 ; ++i) { cout << "bucket #" << i << " has " << c.bucket_size (i) << " elements.\n" ; } string target = get_a_target_string (); { timeStart = clock (); auto pItem = ::find (c.begin (), c.end (), target); cout << "::find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " << endl; } { timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, " << *pItem << endl; else cout << "not found! " <<endl; } } }
使用容器 unordered_map(C++11新增) 相比于 unordered_multimap ,不可以放重复的元素,一个 key 只可以对应一个 value 底层由 hashtable(哈希表)实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <unordered_map> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <iostream> #include <ctime> namespace star16{ void test_unordered_map (long & value) { cout << "\ntest_unordered_map().......... \n" ; unordered_map<long , string> c; char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , rand ()); c[i] = string (buf); } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "milli-seconds : " << (clock ()-timeStart) << endl; cout << "unordered_map.size()= " << c.size () << endl; cout << "unordered_map.max_size()= " << c.max_size () << endl; long target = get_a_target_long (); timeStart = clock (); auto pItem = c.find (target); cout << "c.find(), milli-seconds : " << (clock ()-timeStart) << endl; if (pItem != c.end ()) cout << "found, value=" << (*pItem).second << endl; else cout << "not found! " << endl; } }
使用容器 hash_set hash_map hash_multiset hash_multimap 以前 GNU_C 编译器所带的库,现在将名字中 hash 改为 unordered,现在属于非标准,仍然可以使用,不过要注意位于哪个资料夹
分配器之测试 容器的背后需要 allocator(分配器)来支撑它对内存的使用,容器有一个默认的分配器
使用 allocator 默认分配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <typename _Tp,typename _Alloc=std::allocator<_Tp>> class vector:protected _Vector_base<_Tp,_Alloc> template <typename _Tp,typename _Alloc=std::allocator<_Tp>> class list:protected _List_base<_Tp,_Alloc> template <typename _Tp,typename _Alloc=std::allocator<_Tp>> class deque:protected _Deque_base<_Tp,_Alloc> template <typename _Key,typename _Compare=std::less<_Key>,typename _Alloc=std::allocator<_Key>> class set template <typename _Key,typename _Tp,typename _Compare=std::less<_Key>, typename _Alloc=std::allocator<std::pair<const _Key,_Tp>>> class map template <class _Value, class _Hash=hash<_Value>, class _Pred=std::equal_to<_Value>, class _Alloc=std::allocator<_Value>> class unordered_set template <class _Key,class _Tp, class _Hash=hash<_Key>, class _Pred=std::equal_to<_Key>, class _Alloc=std::allocator<std::pair<const _Key,_Tp>>> class unordered_map
std::allocator 以外的 allocator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 #include <list> #include <stdexcept> #include <string> #include <cstdlib> #include <cstdio> #include <algorithm> #include <iostream> #include <ctime> #include <cstddef> #include <memory> #include <ext\array_allocator.h> #include <ext\mt_allocator.h> #include <ext\debug_allocator.h> #include <ext\pool_allocator.h> #include <ext\bitmap_allocator.h> #include <ext\malloc_allocator.h> #include <ext\new_allocator.h> namespace star20{ void test_list_with_special_allocator () { cout << "\ntest_list_with_special_allocator().......... \n" ; list<string, allocator<string>> c1; list<string, __gnu_cxx::malloc_allocator<string>> c2; list<string, __gnu_cxx::new_allocator<string>> c3; list<string, __gnu_cxx::__pool_alloc<string>> c4; list<string, __gnu_cxx::__mt_alloc<string>> c5; list<string, __gnu_cxx::bitmap_allocator<string>> c6; int choice; long value; cout << "select: " ; cin >> choice; if ( choice != 0 ) { cout << "how many elements: " ; cin >> value; } char buf[10 ]; clock_t timeStart = clock (); for (long i=0 ; i< value; ++i) { try { snprintf (buf, 10 , "%d" , i); switch (choice) { case 1 : c1. push_back (string (buf)); break ; case 2 : c2. push_back (string (buf)); break ; case 3 : c3. push_back (string (buf)); break ; case 4 : c4. push_back (string (buf)); break ; case 5 : c5. push_back (string (buf)); break ; case 6 : c6. push_back (string (buf)); break ; default : break ; } } catch (exception& p) { cout << "i=" << i << " " << p.what () << endl; abort (); } } cout << "a lot of push_back(), milli-seconds : " << (clock ()-timeStart) << endl; int * p; allocator<int > alloc1; p = alloc1. allocate (1 ); alloc1. deallocate (p,1 ); __gnu_cxx::malloc_allocator<int > alloc2; p = alloc2. allocate (1 ); alloc2. deallocate (p,1 ); __gnu_cxx::new_allocator<int > alloc3; p = alloc3. allocate (1 ); alloc3. deallocate (p,1 ); __gnu_cxx::__pool_alloc<int > alloc4; p = alloc4. allocate (2 ); alloc4. deallocate (p,2 ); __gnu_cxx::__mt_alloc<int > alloc5; p = alloc5. allocate (1 ); alloc5. deallocate (p,1 ); __gnu_cxx::bitmap_allocator<int > alloc6; p = alloc6. allocate (3 ); alloc6. deallocate (p,3 ); } }
源代码之分布(VC,GCC) C++ STL标准只规定了统一的接口,未明确指出实现,但是编译器厂商因为性能优势大部分实现相同,如 set 底层采用红黑树实现
标准库版本,Visual C++ files layout …\include STL标准库文件 …\include\cliext 编译器扩展文件 eg: D:\VSworkplace\VS\VC\Tools\MSVC\14.35.32215\include
标准库版本,GNU C++ files layout …\4.9.2\include …\include\c++ …\include\c++\bits STL标准库文件 …\include\c++\ext 编译器扩展文件 eg: S:\Dev-Cpp\Dev-Cpp\Dev-Cpp\MinGW64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++
OOP(面向对象编程) vs. GP(泛型编程) OOP (Object-Oriented programming) vs. GP (Generic Programming)
OOP企图将 datas 和 methods 关联在一起 1 2 3 4 5 template <class T , class Alloc =alloc>class list { ... void sort (); };
为什么 list 不能使用 ::sort() 排序 list 的 Iterator 不是 RandomAccessIterator(随机访问迭代器),是 BidirectionalIterator(双向迭代器) 容器自身带 sort 函数时,一定用自身带的,没有才使用 STL 全局函数 sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <class RandomAccessIterator >inline void sort (RandomAccessIterator first, RandomAccessIterator last) { if (first != last) { __introsort_loop(first, last, value_type (first),__lg(last - first) * 2 ); __final_insertion_sort(first, last); } } template <class RandomAccessIterator , class T , class Size >void __introsort_loop(RandomAccessIterator first, RandomAccessIterator last, T*, Size depth_limit) { ... RandomAccessIterator cut = __unguarded_partition (first, last, T (__median(*first, *(first + (last - first)/2 ), *(last - 1 )))); ... }
GP却是将 datas 和 methods 分开来 Data Structures (Containers)
1 2 3 4 5 6 7 8 9 10 template <class T , class Alloc =alloc>class vector{ ... }; template <class T , class Alloc =alloc, size_t BufSiz=0 >class deque{ ... };
Algorithms
1 2 3 4 5 6 7 8 9 10 11 template <typename _RandomAccessIterator>inline void sort (_RandomAccessIterator __first, _RandomAccessIterator __last) { ... } template <typename _RandomAccessIterator, typename _Compare>inline void sort (_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { ... }
采用 GP: Containers 和 Algorithm 团队可各自闭门造车,其间以 Iterator 沟通即可 Algorithm 通过 Iterators 确定操作范围,并通过 Iterators 取用 Container 元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <class T >inline const T& min (const T& a, const T& b) { return b < a ? b : a; } template <class T >inline const T& max (const T& a, const T& b) { return a < b ? b : a; } template <class T , class Compare >inline const T& min (const T& a,const T& b, Compare comp) { return comp (b, a) ? b : a; } template <class T , class Conpare >inline const T& max (const T& a,const T& b, Compare comp) { return comp (a, b) ? b : a; }
所有 algorithms,其内最终涉及元素本身 的操作,无非就是比大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 bool strLonger (const string& s1, const string& s2) { return s1. size () < s2. size (); } cout << "max of zoo and hello : " << max (string ("zoo" ), string ("hello" )) << endl; cout << "longest of zoo and hello : " << max (string ("zoo" ), string ("hello" ), strLonger) << endl; template <class T >inline const T& max (const T& a, const T& b) { return a < b ? b : a; } template <class T , class Compare >inline const T& max (const T& a, const T& b, Compare comp) { return comp (a, b) ? b : a; }
技术基础:操作符重载 and 模板(泛化,全特化,偏特化) Operator Overloading,操作符重载 资料网站:operator overloading - cppreference.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <class T , class Ref . class Ptr >struct __list_iteraotr { typedef __list_iterator<T, Ref, Ptr> self; typedef bidirectional_iterator_tag iterator_category; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef __list_node<T>* link_type; typedef ptrdiff_t difference_type; link_type node; reference operator *() const { return (*node).data; } pointer operator ->() const { return &(operator *()); } self& operator ++() { node = (link_type)((*node).next); return * this ; } self operator ++(int ) { self tmp = *this ; ++*this ; return tmp; } ... }
Class Templates,类模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <typename T>class complex { public : complex (T r = 0 , T i = 0 ) : re (r), im (i) { } complex& operator += (const complex&); T real () const { return re; } T imag () const { return im; } private : T re, im; friend complex& __dopal (complex*, const complex&); }; { complex<double > c1 (2.5 , 1.5 ) ; complex<int > c2 (2 , 6 ) ; ... }
Function Templates,函数模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class stone { public : stone (int w, int h, int we) : _w(w), _h(h), _weight(we) { } bool operator <(const stone& rhs) const { return _weight < rhs._weight; } private : int _w, _h, _weight; }; template <class T >inline const T& min (const T& a, const T& b) { return b < a ? b : a; } { stone r1 (2 , 3 ) , r2 (3 , 3 ) , r3 ; r3 = min (r1, r2); }
Member Templates,成员模板 Specialization,特化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 template <class type >struct __type_traits { typedef __true_type this_dummy_member_must_be_first; typedef __false_type has_trivial_default_constructor; typedef __false_type has_trivial_copy_constructor; typedef __false_type has_trivial_assignment_operator; typedef __false_type has_trivial_destructor; typedef __false_type is_POD_type; }; template <> struct __type_traits <int > { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; template <> struct __type_traits <double > { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; { __type_traits<Foo>::has_trivial_destructor __type_traits<int >::has_trivial_destructor __type_traits<double >::has_trivial_destructor }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 template <class Key > struct hash { };__STL_TEMPLATE_NULL struct hash <char > { size_t operator () (char x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <short > { size_t operator () (short x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned short > { size_t operator () (unsigned short x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <int > { size_t operator () (int x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned int > { size_t operator () (unsigned int x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <long > { size_t operator () (long x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned long > { size_t operator () (unsigned long x) const { return x; } }; { hash <Foo>(); int i=hash <int >()(32 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <typename _Tp> class allocator ;template <> class allocator <void >{ public : typedef size_t size_type; typedef ptrdiff_t difference_type; typedef void * pointer; typedef const void * const_pointer; typedef void value_type; template <typename _Tp1> struct rebind { typedef allocator<_Tp1> other; }; };
Partial Specialization,偏特化 1 2 3 4 5 6 7 8 9 10 11 12 13 template <class T , class Alloc = alloc>class vector{ ... }; template <class Alloc >class vector <bool , Alloc> { ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 template <class Iterator >struct iterator_traits { typedef typename Iterator::iterator_category iterator_category; typedef typename Iterator::value_type value_type; typedef typename Iterator::difference_type difference_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; }; template <class T >struct iterator_traits <T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; }; template <class T >struct iterator_traits <const T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef const T* pointer; typedef const T& reference; };
分配器 allocators operator new() 和 malloc() 所有分配动作最终都会跑到 operator new,operator new 又会调用 malloc
分配的内存如上图,所申请的空间大小为 size(浅蓝色部分), malloc 会搭配放更多的东西(称为Overhead),详情见内存管理 申请的空间越小,Overhead所占的比例就越高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void *operator new (size_t size, const std::nothrow _t &) _THROW0 () { void *p; while ((p = malloc (size)) == 0 ) { _TRY_BEGIN if (_callnewh(size)==0 ) break ; _CATCH(std::bad_alloc) return (0 ); _CATCH_END } return (p); }
1 2 3 4 5 6 7 inline void * _RTLENTRY operator new (size_t size, const std::nothrow_t &) { size = size ? size : 1 ; return malloc (size); }
VC6 VC6+ 的 allocator 只是以 ::operator new 和 ::operator delete 完成 allocate() 和 deallocate(),没有任何特殊设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <class _Ty , class _A = allocator<_Ty> >class vector{ ... }; template <class _Ty , class _A = allocator<_Ty> >class list{ ... }; template <class _Ty , class _A = allocator<_Ty> >class deque{ ... }; template <class _K , class _Pr = less<_K>, class _A = allocator<_K> >class set { ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #ifndef _FARQ #define _FARQ #define _PDFT ptrdiff_t #define _SIZT size_t #endif #define _POINTER_X(T,A) T_FARQ * #define _REFERENCE_X(T,A) T_FARQ & template <class _Ty >class allocator { public : typedef _SIZT size_type; typedef _PDFT difference_type; typedef _Ty _FARQ *pointer; typedef _Ty value_type; pointer allocate (size_type _N, const void *) { return (_Allocate((difference_type)_N, (pointer)0 )); } void deallocate (void _FARQ *_P, size_type) { operator delete (_P) ; }}; template <class _Ty > inline _Ty _FARQ *_Allocate(_PDFT _N, _Ty _FARQ *){ if (_N < 0 ) _N = 0 ; return ((_Ty _FARQ *)operator new ((_SIZT)_N * sizeof (_Ty))); } int * p = allocator <int >().allocate (512 , (int *)0 );allocator <int >().deallocate (p, 512 );
BC5 BC++ 的 allocator 只是以 ::operator new 和 ::operator delete 完成 allocate() 和 deallocate(),没有任何特殊设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <class T , class Allocator _RWSTD_COMPLEX_DEFAULT(allocator<T>) >class vector ... template <class T , class Allocator _RWSTD_COMPLEX_DEFAULT(allocator<T>) >class list ...template <class T , class Allocator _RWSTD_COMPLEX_DEFAULT(allocator<T>) >class deque ...#define _RWSTD_COMPLEX_DEFAULT(a) = a template <class T , class Allocator = allocator<T> >class vector ... template <class T, class Allocator = allocator<T> >class list ...template <class T, class Allocator = allocator<T> >class deque ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <class T >class allocator { public : typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T value_type; pointer allocate (size_type n, allocator<void >::const_pointer = 0 ) { pointer tmp = _RWSTD_STATIC_CAST(pointer, (::operator new (_RWSTD_STATIC_CAST(size_t , (n * sizeof (value_type)))))); _RWSTD_THROW_NO_MSG(tmp == 0 , bad_alloc); return tmp; } void deallocate (pointer p, size_type) { ::operator delete (p) ; } ... }; int * p = allocator <int >().allocate (512 );allocator <int >().deallocate (p,512 );
G2.9 GCC 2.9 的 allocator 只是以 ::operator new 和 ::operator delete 完成 allocate() 和 deallocate(),没有任何特殊设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 template <class T >class allocator { public : typedef T value_type; typedef T* pointer; typedef size_t size_type; typedef ptrdiff_t difference_type; pointer allocate (size_type n) { return ::allocate ((difference_type)n, (pointer)0 ); } void deallocate (pointer p) { ::deallocate (p); } }; template <class T >inline T* allocate (ptrdiff_t size, T*) { set_new_handler (0 ); T* tmp =(T*)(::operator new ((size_t )(size*sizeof (T)))); if (tmp == 0 ) { cerr << "out of memory" << endl; exit (1 ); } return tmp; } template <class T >inline void deallocate (T* buffer) { ::operator delete (buffer) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <class T , class Alloc = alloc> class vector { ... }; template <class T , class Alloc = alloc>class list { ... }; template <class T , class Alloc = alloc, size_t BufSiz = 0 >class deque { ... }; template <class Key , class T , class Compare = less<Key>, class Alloc = alloc>class map { ... }; template <class Key , class Compare = less<Key>, class Alloc = alloc>class set { ... }; void * p=alloc::allocate (512 ); alloc::deallocate (p,512 );
G2.9 所附的标准库,其 alloc 实现如下(<stl_alloc.h>),源代码及详细介绍见内存管理 设计十六条链表,每一条链表负责某一种特定大小的区块,用链表串起来 第0号链表负责8个字节大小的区块,第7号链表负责8*8=64个字节大小的区块,即第几个*8个字节 函数申请内存,会先去相应大小的链表寻找空闲区块,如果没有,则链表申请很大一块内存,然后做切割,分给申请的函数,这样每个切割的内存都不带 Overhead,减少 Overhead 所占比例
G4.9 1 2 3 4 5 6 template <typename _Tp, typename _Alloc = std::allocator<_Tp> >class vector : protected _Vector_base<_Tp, _Alloc>{ ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <typename _Tp>class allocator : public __allocator_base<_Tp>{ ... }; #define __allocator_base __gnu_cxx::new_allocator template <typename _Tp>class new_allocator { ... pointer allocate (size_type __n, const void * = 0 ) { if (__n > this ->max_size ()) std::__throw_bad_alloc(); return static_cast <_Tp*>(::operator new (__n * sizeof (_Tp))); } void deallocate (pointer __p, size_type) { ::operator delete (__p) ; } ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class __pool_alloc_base { protected : enum { _S_align = 8 }; enum { _S_max_bytes = 128 }; enum { _S_free_list_size = (size_t )_S_max_bytes / (size_t )_S_align }; union _Obj { union _Obj * _M_free_list_link; char _M_client_data[1 ]; }; static _Obj* volatile _S_free_list[_S_free_list_size]; ... } template <typename _Tp>class __pool_alloc : private __pool_alloc_base{ ... }; vector<string, __gnu_cxx::__pool_alloc<string>> vec;
容器之间的实现关系与分类 容器——结构与分类 Sequence Containers(序列式容器) Associative Containers(关联式容器):标准未规定关联式容器底层实现采用红黑树,但是因为红黑树性能好,底层实现采用了红黑树
Unordered Containers(无序容器)属于 Associative Containers
Array、Forward-List、Unordered Containers 为 C++11 新增
容器,结果与分类 本图以缩排 形式表达“基层与衍生层”的关系 这里所谓衍生,并非继承(inheritance)而是复合(composition) 蓝色框内是容器本身大小,即容器内控制整个数据结构的所需数据大小,与容器内存储的元素大小和个数无关
在 C++11 中,slist 名为 forward_list,hash_set,hash_map 名为 unordered_set,unordered_map hash_multiset,hash_multimap 名为 unordered_multiset,unordered_multimap;且新添 array
深度探索 list 容器 list G2.9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 template <class T >struct __list_node { typedef void * void_pointer; void_pointer prev; void_pointer next; T data; }; template <class T , class Ref , class Ptr >struct __list_iterator { typedef T value_type; typedef Ptr pointer; typedef Ref reference; ... }; template <class T , class Alloc = alloc>class list { protected : typedef __list_node<T> list_node; public : typedef list_node* link_type; typedef __list_iterator<T,T&,T*> iterator; protected : link_type node; ... };
list’s iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 template <class T >struct __list_node { typedef void * void_pointer; void_pointer prev; void_pointer next; T data; }; template <class T , class Ref , class Ptr >struct __list_iterator { typedef __list_iterator<T, Ref, Ptr> self; typedef bidirectional_iterator_tag iterator_category; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef __list_node<T>* link_type; typedef ptrdiff_t difference_type; link_type node; reference operator *() const { return (*node).data; } pointer operator ->() const { return &(operator *()); } self& operator ++() { node = (link_type)((*node).next); return *this ; } self operator ++(int ) { self tmp = *this ; ++*this ; return tmp; } ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 list<int > c; ... auto ite = c.begin ();++++ite; ++(++ite); int i (6 ) ;++++i; ++(++i);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 reference operator *() const { return (*node).data; } pointer operator ->() const { return &(operator *()); } list<Foo>::iterator ite; ... *ite; ite->method (); ite->field = 7 ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 template <class T , class Alloc = alloc>class list { public : typedef __list_iterator<T,T&,T*> iterator; ... }; template <class T , class Ref , class Ptr >struct __list_iterator { typedef Ptr pointer; typedef Ref reference; ... }; template <class T >struct __list_node { typedef void * void_pointer; void_pointer prev; void_pointer next; T data; }; template <typename _Tp, typename _Alloc = std::allocator<_Tp>>class list : protected _List_base<_Tp,_Alloc>{ public : typedef _List_iterator<_Tp> iterator; ... }; template <typename _Tp>struct _List_iterator { typedef _Tp* pointer; typedef _Tp& reference; ... }; struct _List_node_base { _List_node_base* _M_next; _List_node_base* _M_prev; }; template <typename _Tp>struct _List_node : public _List_node_base{ _Tp _M_data; };
迭代器的设计原则和 Iterator Traits 的作用与设计 Iterator 需要遵循的原则 iterators 必须有能力回答 algorithms 的提问 这样的提问在 C++ 标准库开发过程中设计出5种,本例出现3种。另两种从未在 C++ 标准库中被使用过:reference 和 pointer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 template <typename _ForwardIterator>inline void rotate (_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { ... std::__rotate(__first, __middle, __last, std::iterator_category (__first)); } template <typename _Iter> inline typename iterator_traits<_Iter>::iterator_category __iterator_category(const _Iter&){ return typename iterator_traits<_Iter>::iterator_category (); } template <typename _RandonAccessIterator>void __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, random_access_iterator_tag) { ... typedef typename iterator_traits<_RandomAccessIterator>::difference_type _Distance; typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType; _Distance __n = __last - __first; _Distance __k = __middle - __firstl ... for (;;) { if (__k < __n - __k) { if (__is_pod(_ValueType) && __k == 1 ) { _ValueType __t = _GLIBCXX_MOVE(*__p) ... } } } }
Iterator 必须提供的5种 associated types 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 template <typename I>inline void algorithm (I first, I last) { ... I::iterator_category I::pointer I::reference I::value_type I::difference_type ... }; template <class T , class Ref , class Ptr >struct __list_iterator { typedef bidirectional_iterator_tag iterator_category; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef ptrdiff_t difference_type; ... }; template <typename _Tp>struct _List_iterator { typedef std::bidirectional_iterator_tag iterator_category; typedef _Tp value_type; typedef _Tp* pointer; typedef _Tp& reference; typedef ptrdiff_t difference_type; ... };
Traits 特性,特徵,特质 解决计算机问题的尚方宝剑:加一个中介层 Iterator Traits 用以分离 class iterators 和 non-class iterators 这个 traits 机器必须有能力分辨它所获得的 iterator 是 (1) class iterator T 或是 (2) native pointer(它被视为一种退化的 iterator ) to T 利用 partial specialization 可达到目标 Non class (template) iterators 亦即 native pointer,无法定义 associated types. 但它的 associated types 其实很直观 class (template) iterators 都有能力定义自己的 associated types
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <typename I,...>void algorithm (...) { typename iterator_traits<I>::value_type v1; } template <class I >struct iterator_traits { typedef typename I::value_type value_type; }; template <class T >struct iterator_traits <T*> { typedef T value_type; }; template <class T >struct iterator_traits <const T*> { typedef T value_type; };
完整的 iterator_traits 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 template <class I >struct iterator_traits { typedef typename I::iterator_category iterator_category; typedef typename I::value_type value_type; typedef typename I::difference_type difference_type; typedef typename I::pointer pointer; typedef typename I::reference reference; }; template <class T >struct iterator_traits <T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; }; template <class T >struct iterator_traits <const T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef const T* pointer; typedef const T& reference; };
各式各样的 Traits
type traits <…/C++/type_traits>
iterator traits <…/C++/bits/stl_iterator.h>
char traits <…/C++/bits/char_traits.h>
allocator traits <…/C++/bits/alloc_traits.h>
pointer traits <…/C++/bits/ptr_traits.h>
array traits <…/C++/array>
vector 深度探索 容器 vector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <class T , class Alloc = alloc>class vector { public : typedef T value_type; typedef value_type* iterator; typedef value_type& reference; typedef size_t size_type; protected : iterator start; iterator finish; iterator end_if_storage; public : iterator begin () { return start; } iterator end () { return finish; } size_type size () const { return size_type (end () - begin ()); } size_type capacity () const { return size_type (end_of_storage-begin ()); } bool empty () const { return begin () == end (); } reference operator [](size_type n) { return *(begin () + n); } reference front () { return *begin (); } reference back () { return *(end () - 1 ); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 void push_back (const T& x) { if (finish != end_of_storage) { construct (finish, x); ++finish; } else insert_aux (end (), x); } template <class T , class Alloc >void vector<T,Alloc>::insert_aux (iterator position, const T& x) { if (finish != end_of_storage) { construct (finish, *(finish - 1 )); ++finish; T x_copy = x; copy_backward (position, finish - 2 , finish - 1 ); *position = x_copy; } else { const size_type old_size = size (); const size_type len = old_size != 0 ? 2 * old_size : 1 ; iterator new_start = data_allocator::allocate (len); iterator new_finish = new_start; try { new_finish = uninitialized_copy (start, position, new_start); construct (new_finish, x); ++new_finish; new_finish = uninitialized_copy (position, finish, new_finish); } catch (...) { destroy (new_start, new_finish); data_allocator::deallocate (new_start, len); throw ; } destroy (begin (), end ()); deallocate (); start = new_start; finish = new_finish; end_of_storage = new_start + len; } }
vector’s iterator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <class T , class Alloc = alloc>class vector { public : typedef T value_type; typedef value_type* iterator; ... }; { vector<int > vec; ... vector<int >::iterator ite = vec.begin (); iterator_traits<ite>::iterator_category; iterator_traits<ite>::difference_type; iterator_traits<ite>::value_type; }
追踪 vector::iterator,发现它就是 _Tp* 外覆一个 iterator adapter,使能支持 5 associated types
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 template <typename _Tp, typename _Alloc = std::allocator<_Tp>>class vector : protected _Vector_base<_Tp, _Alloc>{ ... typedef _Vector_base<_Tp,_Alloc> _Base; typedef typename _Base::pointer pointer; typedef __gnu_cxx::__normal_iterator<pointer,vector> iterator; ... }; using std::iterator_traits;using std::iterator;template <typename _Iterator, typename _Container>class __normal_iterator { protected : _Iterator _M_current; typedef iterator_traits<_Iterator> __traits_type; public : typedef _Iterator iterator_type; typedef typename __traits_type::iterator_category iterator_category; typedef typename __traits_type::value_type value_type; typedef typename __traits_type::difference_type difference_type; typedef typename __traits_type::reference reference; typedef typename __traits_type::pointer pointer; _GLIBCXX_CONSTEXPR __normal_iterator() _GLIBCXX_NOEXCEPT : _M_current(_Iterator()) { } ... } template <typename _Tp, typename _Alloc>struct _Vector_base { typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type; typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer; ... } template <typename _Tp>class allocator : public __glibcxx_base_allocator<_Tp>{ public : typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <typename _Tp, typename _Alloc = std::allocator<_Tp>>class vector : protected _Vector_base<_Tp, _Alloc>{ ... typedef _Vector_base<_Tp, _Alloc> _Base; typedef typename _Base::pointer pointer; typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator; ... } { vector<int > vec; ... vector<int >::iterator ite = vec.begin (); iterator_traits<ite>::iterator_category; iterator_traits<ite>::difference_type iterator_traits<ite>::value_type }
array、forward_list 深度探索 容器 array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <typename _Tp, std::size_t _Nm>struct array { typedef _Tp value_type; typedef _Tp* pointer; typedef value_type* iterator; value_type _M_instance[_Nm ? _Nm : 1 ]; iterator begin () { return iterator (&_M_instance[0 ]); } iterator end () { return iterator (&_M_instance[_Nm]); } ... } { array<int , 10> myArray; auto ite = myArray.begin (); ite += 3 ; cout << *ite; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 { int a[100 ]; int [100 ] b; typedef int T[100 ]; T c; } template <typename _Tp, std::size_t _Nm>struct __array_traits { typedef _Tp _Type[_Nm]; static constexpr _Tp& _S_ref(const _Type& __t , std::size_t __n) noexcept { return const_cast <Tp&>(__t [__n]); } }; template <typename _Tp, std::size_t _Nm>struct array { typedef _Tp value_type; typedef value_type* pointer; typedef value_type& reference; typedef value_type* iterator; typedef std::size_t size_type; typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type; typename _AT_Type::_Type _M_elems; iterator begin () noexcept { return iterator (data ()); } iterator end () noexcept { return iterator (data () + _Nm); } constexpr size_type size () const noexcept { return _Nm; } reference operator [](size_type __n) noexcept { return _AT_Type::_S_ref(_M_elems, __n); } reference at (size_type __n) { if (__n >= _Nm) std::__throw_out_of_range_fmt(...); return _AT_Type::_S_ref(_M_elems, __n); } pointer data () noexcept { return std::__addressof(_AT_Type::_S_ref(_M_elems, 0 )); } ... };
容器 forward_list
deque、queue 和 stack 深度探索 容器 deque
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <class T , class Alloc =alloc, size_t BufSiz=0 > class deque { public : typedef T value_type; typedef __deque_iterator<T,T&,T*,BufSiz> iterator; protected : typedef pointer* map_pointer; protected : iterator start; iterator finish; map_pointer map; size_type map_size; public : iterator begin () { return start; } iterator end () { return finish; } size_type size () const { return finish - start; } ... }; inline size_t __deque_buf_size(size_t n, size_t sz){ return n != 0 ? n : (sz < 512 ? size_t (512 / sz) : size_t (1 )); }
deque’iterator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <class T , class Ref , class Ptr , size_t BufSiz>struct __deque_iterator { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T** map_pointer; typedef __deque_iterator self; T* cur; T* first; T* last; map_pointer node; ... };
deque<T>::insert() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 iterator insert (iterator position, const value_type& x) { if (postion.cur == start.cur) { push_front (x); return start; } else if (position.cur == finish.cur) { push_back (x); iterator tmp = finish; --tmp; return tmp; } else { return insert_aux (position, x); } } template <class T , class Alloc , size_t BufSize>typename deque<T, Alloc, BufSize>::iteratordeque<T, Alloc, BufSize>::insert_aux (iterator pos, const value_type& x) { difference_type index = pos - start; value_type x_copy = x; if (index < size () / 2 ) { push_front (front ()); ... copy (front2, pos1, front1); } else { push_back (back ()); ... copy_backward (pos, back2, back1); } *pos = x_copy; return pos; }
deque 如何模拟连续空间 全都是 deque iterators 的功劳
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 reference operator [](size_type n) { return start[difference_type (n)]; } reference front () { return *start; } reference back () { iterator tmp = finish; --tmp; return *tmp; } size_type size () const { return finish - start; } bool empty () const { return finish == start; } reference operator *() const { return *cur; } pointer operator ->() const { return &(operator *()); } difference_type operator -(const self& x) const { return difference_type (buffer_size ()) * (node - x.node - 1 ) + (cur - first) + (x.last - x.cur); } void set_node (map_pointer new_node) { node = new_node; first = *new_node; last = first + difference_type (buffer_size ()); } self& operator ++() { ++cur; if (cur == last) { set_node (node + 1 ); cur = first; } return *this ; } self operator ++(int ) { self tmp = *this ; ++*this ; return tmp; } self& operator --() { if (cur == first) { set_node (node - 1 ); cur = last; } --cur; return *this ; } self operator --(int ) { self tmp = *this ; --*this ; return tmp; } self& operator +=(difference_type n) { difference_type offset = n + (cur - first); if (offset >= 0 && offset < difference_type (buffer_size ())) cur += n; else { difference_type node_offset = offset > 0 ? offset / difference_type (buffer_size ()) : -difference_type ((-offset - 1 ) / buffer_size ()) - 1 ; set_node (node + node_offset); cur = first + (offset - node_offset * difference_type (buffer_size ())); } return *this ; } self operator +(difference_type n) const { self tmp = *this ; return tmp += n; } self& operator -=(difference_type n) { return *this += -n; } self operator -(difference_type n) const { self tmp = *this ; return tmp -= n; } reference operator [](difference_type n) const { return *(*this + n); }
deque 控制中心 map 使用 vector 存储,当空间不足时,进行扩充,原来的值复制到新空间的中段,这样才能向左和向右扩充缓冲区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 template <typename _Tp, typename _Alloc>class _Deque_base { protected : struct _Deque_impl : public _Tp_alloc_type { _Tp** _M_map; size_t _M_map_size; iterator _M_start; iterator _M_finish; ... }; ... }; #define _GLIBCXX_DEQUE_BUF_SIZE 512 inline size_t __deque_buf_size(size_t __size){ return (__size < _GLIBCXX_DEQUE_BUF_SIZE ? size_t (_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t (1 )); } template <typename _Tp, typename _Alloc = std::allocator<_Tp>>class deque : protected _Deque_base<_Tp, _Alloc> { ... static size_t _S_buffer_size() { return __deque_buf_size(sizeof (_Tp)); } };
容器 queue queue 内含一个 deque,封住一部分功能 在技术上,queue 当作一个 container adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <class T , class Sequence =deque<T>>class queue { ... public : typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_reference const_reference; protected : Sequence c; public : bool empty () const { return c.empty (); } size_type size () const { return c.size (); } reference front () { return c.front (); } const_reference front () const { return c.front (); } reference back () { return c.back (); } const_reference back () const { return c.back (); } void push (const value_type& x) { c.push_back (x); } void pop () { c.pop_front (); } };
容器 stack stack 内含一个 deque,封住一部分功能 在技术上,stack 当作一个 container adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <class T , class Sequence =deque<T>>class stack { ... public : typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_reference const_reference; protected : Sequence c; public : bool empty () const { return c.empty (); } size_type size () const { return c.size (); } reference top () { return c.back (); } const_reference top () const { return c.back (); } void push (const value_type& x) { c.push_back (x); } void pop () { c.pop_back (); } };
queue 和 stack,关于其 iterator 和底层结构 只要底部数据结构能够提供 queue 和 stack 转调用所需要的函数,这个容器就能作为底部支撑
stack 或 queue 都不允许遍历,也不提供 iterator 1 2 stack<string>::iterator ite; queue<string>::iterator ite;
stack 和 queue 都可选择 list 或 deque 做为底层结构 默认的作为底部支撑(deque)比较快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 { stack<string, list<string>> c; for (long i=0 ; i< 10 ; ++i) { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; c.pop (); cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; } { queue<string, list<string>> c; for (long i=0 ; i< 10 ; ++i) { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; c.pop (); cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; }
stack 可选择 vector 做为底层结构 1 2 3 4 5 6 7 8 9 10 11 12 { stack<string, vector<string>> c; for (long i=0 ; i< 10 ; ++i) { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; c.pop (); cout << "stack.size()= " << c.size () << endl; cout << "stack.top()= " << c.top () << endl; }
queue 不可选择 vector 做为底层结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { queue<string, vector<string>> c; for (long i=0 ; i< 10 ; ++i) { snprintf (buf, 10 , "%d" , rand ()); c.push (string (buf)); } cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; cout << "queue.size()= " << c.size () << endl; cout << "queue.front()= " << c.front () << endl; cout << "queue.back()= " << c.back () << endl; }
stack 和 queue 都不可选择 set 或 map 做为底层结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { stack<string, set<string>> c; for (long i=0 ; i< 10 ; ++i) { snprintf (buf, 10 , "%d" , rand ()); } cout << "stack.size()= " << c.size () << endl; cout << "stack.size()= " << c.size () << endl; } { stack<string, map<string>> c; queue<string, map<string>> c; }
RB-tree 深度探索 容器 rb_tree Red-Black tree(红黑树)是平衡二元搜寻树(balanced binary search tree)中常被使用的一种 平衡二元搜寻树的特徵:排列规则有利 search 和 insert,并保持适度平衡——无任何节点过深
rb_tree 提供 “遍历” 操作及 iterators 按正常规则(++ite)遍历,便能获得排序状态(sorted)(中序遍历红黑树)
我们不应 使用 rb_tree 的 iterators 改变元素值(因为元素有其严谨排列规则) 编程层面(programming level)并未阻绝此事 。如此设计是正确的,因为 rb_tree 即将为 set 和 map 服务(做为其底部支持),而 map 允许元素的 data 被改变,只有元素的 key 才是不可被改变的
rb_tree 提供两种 insertion 操作:insert_unique() 和 insert_equal() 前者表示节点的 key 一定在整个 tree 中独一无二,否则安插失败(无作用,不会报错);后者表示节点的 key 可重复
元素本身是可以放两个东西的,一个是 key,一个是 data,,合起来叫 value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 template <class Arg , class Result >struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class T > struct identity : public unary_function<T, T> { const T& operator () (const T& x) const { return x; } }; template <class Arg1 , class Arg2 , class Result >struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; template <class T >struct less : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x < y; } }; template <class Key , class Value , class KeyOfValue , class Compare , class Alloc = alloc>class rb_tree { protected : typedef __rb_tree_node<Value> rb_tree_node; ... public : typedef rb_tree_node* link_type; ... protected : size_type node_count; link_type header; Compare key_compare; ... }; rb_tree<int , int , identity<int >, less<int >, alloc> myTree;
容器 rb_tree,用例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 rb_tree<int , int , identity<int >, less<int >> itree; cout << itree.empty () << endl; cout << itree.empty () << endl; itree.insert_unique (3 ); itree.insert_unique (8 ); itree.insert_unique (5 ); itree.insert_unique (9 ); itree.insert_unique (13 ); itree.insert_unique (5 ); cout << itree.empty () << endl; cout << itree.size () << endl; cout << itree.count (5 ) << endl; itree.insert_equal (5 ); itree.insert_equal (5 ); cout << itree.size () << endl; cout << itree.count (5 ) << endl;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 _Rb_tree<int , int , _Identity<int >, less<int >> itree; cout << itree.empty () << endl; cout << itree.size () << endl; itree._M_insert_unique(3 ); itree._M_insert_unique(8 ); itree._M_insert_unique(5 ); itree._M_insert_unique(9 ); itree._M_insert_unique(13 ); itree._M_insert_unique(5 ); cout << itree.empty () << endl; cout << itree.size () << endl; cout << itree.count (5 ) << endl; itree._M_insert_equal(5 ); itree._M_insert_equal(5 ); cout << itree.size () << endl; cout << itree.count (5 ) << endl;
G4.9 Header and body 实现手法,header—— _Rb_tree 包含一个指针或者一个单一的东西来表现它的实现手法 impl,本身无太多设计,真正实作的设计位于 body,body——_Rb_tree_impl color 是 Enumeration(枚举类型),4个字节 _M_color(_Rb_tree_color 4字节)+_M_parent(_Base_ptr 4字节)+_M_right(_Base_ptr 4字节)+_M_left(_Base_ptr 4字节)+_M_value_field(_Val 4字节)+_M_node_count(size_type 4字节)=24字节
set、multiset 深度探索 容器 set, multiset set/multiset 以 rb_tree 为底层结构,因此有元素自动排序 特性 排序的依据是 key,而 set/multiset 元素的 value 和 key 合一:value 就是 key
set/multiset 提供 “遍历” 操作及 iterators 按正常规则(++ite)遍历,便能获得排序状态(sorted)
我们无法 使用 set/multiset 的 iterators 改变元素值(因为 key 有其严谨排列规则) set/multiset 的 iterator 是其底部的 RB tree 的 const-iterator,就是为了禁止 user 对元素赋值
set 元素的 key 必须独一无二,因此其 insert() 用的是 rb_tree 的 insert_unique() multiset 元素的 key 可以重复,因此其 insert() 用的是 rb_tree 的 insert_equal()
容器 set set 的所有操作,都转呼叫底层 t(rb_tree)的操作 从这层意义看,set 未尝不是个 container adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <class Key , class Compare = less<Key>, class Alloc = alloc>class set { public : typedef Key key_type; typedef Key value_type; typedef Compare key_compare; typedef Compare value_compare; private : typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type; rep_type t; public : typedef typename rep_type::const_iterator iterator; ... }; { set<int > iset; } { set<int , less<int >, alloc> iset; } { template <int , int , identity<int >, less<int >, alloc> class rb_tree ; }
容器 set, in VC6 VC6 不提供 identity()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <class _K , class _Pr = less<_K>, class _A = allocator<_K> >class set { public : typedef set<_K, _Pr, _A> _Myt; typedef _K value_type; struct _Kfn : public unary_function<value_type, _K> { const _K& operator () (const value_type& _X) const { return (_X); } } ; typedef _Pr value_compare; typedef _K key_type; typedef _Pr key_compare; typedef _A allocator_type; typedef _Tree<_K, value_type, _Kfn, _Pr, _A> _Imp; ... protected : _Imp _Tr; };
使用容器 multiset 跳转到使用容器 multiset
map、multimap 深度探索 容器 map, multimap map/multimap 以 rb_tree 为底层结构,因此有元素自动排序 特性 排序的依据是 key
map/multimap 提供 “遍历” 操作及 iterators 按正常规则(++ite)遍历,便能获得排序状态(sorted)
我们无法 使用 map/multimap 的 iterators 改变元素的 key(因为 key 有其严谨排列规则),但可以 用它来改变元素的 data 因此 map/multimap 内部自动将 user 指定的 key type 设为 const,如此便能禁止 user 对元素的 key 赋值
map 元素的 key 必须独一无二,因此其 insert() 用的是 rb_tree 的 insert_unique() multimap 元素的 key 可以重复,因此其 insert() 用的是 rb_tree 的 insert_equal()
容器 map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <class Key , class T , class Compare = less<Key>, class Alloc=alloc>class map { public : typedef Key key_type; typedef T data_type; typedef T mapped_type; typedef pair<const Key, T> value_type; typedef Compare key_compare; private : typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type; rep_type t; public : typedef typename rep_type::iterator iterator; ... }; { map<int , stirng> imap; } { map<int , string, less<int >, alloc> imap; } { template <int , pair<const int , string>, select1st<pair<const int , string>>, less<int >, alloc> class rb_tree ; }
容器 map, in VC6 VC6 不提供 select1st()
1 2 3 4 5 6 7 8 9 10 11 12 13 template <class Arg , class Result >struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Pair >struct select1st : public unary_function<Pair, typename Pair::first_type> { const typename Pair::first_type& operator () (const Pair& x) const { return x.first; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <class _K , class _Ty , class _Pr = less<_K>, class _A = allocator<_Ty> >class map { public : typedef map<_K, _Ty, _Pr, _A> _Myt; typedef pair<const _K, _Ty> value_type; struct _Kfn : public unary_function<value_type, _K> { const _K& operator () (const value_type& _X) const { return (_X.first); } }; ... typedef _Tree<_K, value_type, _Kfn, _Pr, _A> _Imp; ... protected : _Imp _Tr; };
容器 map,独特的 operator[] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 mapped_type& operator [](const key_type& __k) { __glibcxx_function_requires(_DefaultConstructibleConcept); iterator __i = lower_bound (__k); if (__i == end () || key_comp ()(__k, (*__i).first)) #if __cplusplus >= 201103L __i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct, std::tuple<const key_type>, std::tuple<>()); #else __i = insert (__i, value_type (__k, mapped_type ())); #endif return (*__i).second; }
使用容器 map 跳转到使用容器 map
容器 multimap 使用容器 multimap 跳转到使用容器 multimap
hashtable 深度探索 容器 hashtable 我们可以使用 hashtable iterators 改变元素的 data,但不能改变元素的 key(因为 hashtable 根据 key 实现严谨的元素排列) Separate Chaining 链表法/分离链接法 rehashing 再散列/按照散列函数把元素重新打散 GNU_C是单向链表 VC是双向链表 散列函数一般采用除留取余法 buckets(篮子)大小刻意为质数,扩充时会选择原来倍数附近的质数
1 2 3 4 5 6 7 8 9 static const unsigned long __stl_prime_list[__stl_num_primes] = { 53 , 97 , 193 , 389 , 769 , 1543 , 3079 , 6151 , 12289 , 24593 , 49157 , 98317 , 196613 , 393241 , 786433 , 1572869 , 3145739 , 6291469 , 12582917 , 25165843 , 50331653 , 100663319 , 201326611 , 402653189 , 805306457 , 1610612741 , 3221225473ul , 429496729lu l };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 template <class Value >struct __hashtable_node { __hashtable_node* next; Value val; }; template <class Value , class Key , class HashFcn , class ExtractKey , class EqualKey , class Alloc >struct __hashtable_iterator {... node* cur; hashtable* ht; }; template <class Value , class Key , class HashFcn , class ExtractKey , class EqualKey , class Alloc = alloc>class hashtable { public : typedef HashFcn hasher; typedef EqualKey key_equal; typedef size_t size_type; private : hasher hash; key_equal equals; ExtractKey get_key; typedef __hashtable_node<Value> node; vector<node*, Alloc> buckets; size_type num_elements; public : size_type bucket_count () const { return buckets.size (); } ... }; { hashtable<const char *, const char *, hash<const char *>, identity<const char *>, eqstr, alloc> ht (50 , hash <const char *>(), eqstr ()); ht.insert_unique ("kiwi" ); ht.insert_unique ("plum" ); ht.insert_unique ("apple" ); } struct eqstr { bool operator () (const char * s1, const char * s1) const { return strcmp (s1, s2) == 0 ; } };
hash-function, hash-code hash function 的目的,就是希望根据元素值算出一个 hash code(一个可进行 modulus 运算的值),使得元素经 hash code 映射之后能够够杂够乱够随机 地置于 hashtable 内。愈是杂乱,愈不容易发生碰撞 如果 hash-function 中放的不是已经写好了,就要以下面这种形式为空的 hash 写一个特化版本,具体内容需要自己设计,但是数据都是由基本类型构成的,可以把数据中的各种基础类型的 hash 结合起来使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 template <class Key > struct hash { };__STL_TEMPLATE_NULL struct hash <char > { size_t operator () (char x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <short > { size_t operator () (short x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned short > { size_t operator () (unsigned short x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <int > { size_t operator () (int x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned int > { size_t operator () (unsigned int x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <long > { size_t operator () (long x) const { return x; } }; __STL_TEMPLATE_NULL struct hash <unsigned long > { size_t operator () (unsigned long x) const { return x; } }; { hash <Foo>(); int i = hash <int >()(32 ); }
注意,标准库没有提供现成的 hash<std::string>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 inline size_t __stl_hash_string(const char * s){ unsigned long h = 0 ; for ( ; *s; ++s) h = 5 *h + *s; return size_t (h); } __STL_TEMPLATE_NULL struct hash <char *> { size_t operator () (const char * s) const { return __stl_hash_string(s); } }; __STL_TEMPLATE_NULL struct hash <const char *> { size_t operator () (const char * s) const { return __stl_hash_string(s); } }; { hashtable<const char *, const char *, hash<const char *>, identity<const char *>, eqstr, alloc> ht (50 , hash <const char *>(), eqstr ()); ht.insert_unique ("kiwi" ); ht.insert_unique ("plum" ); ht.insert_unique ("apple" ); }
modulus 运算 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 iterator find (const key_type& key) { size_type n = bkt_num_key (key); ... } iterator count (const key_type& key) const { const size_type n = bkt_num_key (key); ... } template <class V , class K , class HF , class ExK , class EqK , class A >__hashtable_iterator<V, K, HF, ExK, EqK, A>& __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator ++() { ... size_type bucket = ht->bkt_num (old->val); ... } size_type bkt_num (const value_type& obj) const { return bkt_num_key (get_key (obj)); } size_type bkt_num (const value_type& obj, size_t n) const { return bkt_num_key (get_key (obj), n); } size_type bkt_num_key (const key_type& key) const { return bkt_num_key (key, buckets.size ()); } size_type bkt_num_key (const key_type& key, size_t n) const { return hash (key) % n; }
hashtable 用例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 template <> struct hash <string>{ size_t operator () (string s) const { return __stl_hash_string(s.c_str ()); } }; { hashtable<string, string, hash<string>, identity<string>, equal_to<string>, alloc> sht (50 , hash <string>(), equal_to <string>()); cout<< sht.size () << endl; cout<< sht.bucket_count () << endl; hashtable< pair<const string, int >, string, hash<string>, select1st< pair<const string, int > >, equal_to<string>, alloc > siht (100 , hash <string>(), equal_to <string>()); cout<< siht.size () << endl; cout<< siht.bucket_count () << endl; siht.insert_unique ( make_pair (string ("jjhou" ),95 ) ); siht.insert_unique ( make_pair (string ("sabrina" ),90 ) ); siht.insert_unique ( make_pair (string ("mjchen" ),85 ) ); cout<< siht.size () << enddl; cout<< siht.bucket_count () << endl; cout << siht.find (string ("sabrina" ))->second << endl; cout << siht.find (string ("jjhou" ))->second << endl; cout << siht.find (string ("mjchen" ))->second << endl; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 template <> struct hash <string> : public __hash_base<size_t , string>{ size_t operator () (const string& __s) const noexcept { return std::_Hash_impl::hash (__s.data (),__s.length ()); } }; template <> struct __is_fast_hash <hash<string>> : std::false_type { }; { _Hashtable< string, string, hash<string>, _Identity<string>, equal_to<string>, alloc> sht (50 , hash <string>(), equal_to <string>()); cout<< sht.size () << endl; cout<< sht.bucket_count () << endl; _Hashtable< pair<const string, int >, string, hash<string>, select1st< pair<const string, int > >, equal_to<string>, alloc > siht (100 , hash <string>(), equal_to <string>()); cout<< siht.size () << endl; cout<< siht.bucket_count () << endl; siht.insert_unique ( make_pair (string ("jjhou" ),95 ) ); siht.insert_unique ( make_pair (string ("sabrina" ),90 ) ); siht.insert_unique ( make_pair (string ("mjchen" ),85 ) ); cout<< siht.size () << enddl; cout<< siht.bucket_count () << endl; cout << siht.find (string ("sabrina" ))->second << endl; cout << siht.find (string ("jjhou" ))->second << endl; cout << siht.find (string ("mjchen" ))->second << endl; }
hash_set、hash_multiset,hash_map、hash_multimap 概念 unordered 容器概念 unordered 容器 容器 unordered_set, unordered_multiset 容器 unordered_map, unordered_multimap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T> > class unordered_set;template <typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T> > class unordered_multiset;template <typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<const Key, T> > > class unordered_map;template <typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<const Key, T> > > class unordered_multimap;
使用容器 unordered_set 跳转到使用容器 unordered_set
算法的形式 C++标准库的算法 从语言层面讲
容器 Container 是个 class template
算法 Algorithm 是个 function template
迭代器 Iterator 是个 class template
仿函数 Functor 是个 class template
适配器 Adapter 是个 class template
分配器 Allocator 是个 class template
Algorithms 看不见 Containers,对其一无所知;所以,它所需要的一切信息都必须从 Iterators 取得,而 Iterators(由 Containers 供应)必须能够回答 Algorithm 的所有提问,才能搭配该 Algorithm 的所有操作 如果 Algorithms 发出问题,Iterators无法回答,那么编译到那一行,编译就会失败报错
1 2 3 4 5 6 7 8 9 10 11 12 template <typename Iterator>Algorithm (Iterator itr1, Iterator itr2) { ... } template <typename Iterator, typename Cmp>Algorithm (Iterator itr1, Iterator itr2, Cmp comp) { ... }
迭代器的分类(category) 各种容器的 iterators 的 iterator_category 1 2 3 4 5 6 7 struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirectional_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirectional_iterator_tag {};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 void _display_category(random_access_iterator_tag){ cout << "random_access_iterator" << endl; } void _display_category(bidirectional_iterator_tag){ cout << "bidirectional_iterator" << endl; } void _display_category(forward_iterator_tag){ cout << "forward_iterator" << endl; } void _display_category(output_iterator_tag){ cout << "output_iterator" << endl; } void _display_category(input_iterator_tag){ cout << "input_iterator" << endl; } template <typename I>void display_category (I itr) { typename iterator_traits<I>::iterator_category cagy; _display_category(cagy); } { cout << "\ntest_iterator_category().......... \n" display_category (array<int ,10 >::iterator ()); display_category (vector<int >::iterator ()); display_category (list<int >::iterator ()); display_category (forward_list<int >::iterator ()); display_category (deque<int >::iterator ()); display_category (set<int >::iterator ()); display_category (map<int ,int >::iterator ()); display_category (multiset<int >::iterator ()); display_category (multimap<int ,int >::iterator ()); display_category (unordered_set<int >::iterator ()); display_category (unordered_map<int ,int >::iterator ()); display_category (unordered_multiset<int >::iterator ()); display_category (unordered_multimap<int ,int >::iterator ()); display_category (istream_iterator <int >()); display_category (ostream_iterator <int >(cout,"" )); }
各种容器的 iterators 的 iterator_category 的 typeid 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 #include <typeinfo> void _display_category(random_access_iterator_tag){ cout << "random_access_iterator" << endl; } void _display_category(bidirectional_iterator_tag){ cout << "bidirectional_iterator" << endl; } void _display_category(forward_iterator_tag){ cout << "forward_iterator" << endl; } void _display_category(output_iterator_tag){ cout << "output_iterator" << endl; } void _display_category(input_iterator_tag){ cout << "input_iterator" << endl; } template <typename I>void display_category (I itr) { typename iterator_traits<I>::iterator_category cagy; _display_category(cagy); cout << "typeid(itr).name()= " << typeid (itr).name () << endl << endl; } { cout << "\ntest_iterator_category_typeid().......... \n" display_category (array<int ,10 >::iterator ()); display_category (vector<int >::iterator ()); display_category (list<int >::iterator ()); display_category (forward_list<int >::iterator ()); display_category (deque<int >::iterator ()); display_category (set<int >::iterator ()); display_category (map<int ,int >::iterator ()); display_category (multiset<int >::iterator ()); display_category (multimap<int ,int >::iterator ()); display_category (unordered_set<int >::iterator ()); display_category (unordered_map<int ,int >::iterator ()); display_category (unordered_multiset<int >::iterator ()); display_category (unordered_multimap<int ,int >::iterator ()); display_category (istream_iterator <int >()); display_category (ostream_iterator <int >(cout,"" )); }
istream_iterator 的 iterator_category 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 { display_category (istream_iterator <int >()); display_category (ostream_iterator <int >(cout,"" )); } template <class T , class Distance = ptrdiff_t >class istream_iterator { public : typedef input_iterator_tag iterator_category; ... }; template <class _Tp , class _CharT = char , class _Traits = char_traits<_CharT>, class _Dist = ptrdiff_t >class istream_iterator { public : typedef input_iterator_tag iterator_category; ... }; template <typename _Tp, typename _CharT = char , typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t >class istream_iterator : public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>{ ... }; template <typename _Category, typename _Tp, typename _Distance = ptrdiff_t , typename _Pointer = _Tp*, typename _Reference = _Tp&> struct iterator{ typedef _Category iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typedef _Pointer pointer; typedef _Reference reference; };
ostream_iterator 的 iterator_category 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 { display_category (istream_iterator <int >()); display_category (ostream_iterator <int >(cout,"" )); } template <class T >class ostream_iterator { public : typedef output_iterator_tag iterator_category; ... }; template <class _Tp , class _CharT = char , class _Traits = char_traits<_CharT> >class ostream_iterator { public : typedef output_iterator_tag iterator_category; ... }; template <typename _Tp, typename _CharT = char , typename _Traits = char_traits<_CharT> >class ostream_iterator : public iterator<output_iterator_tag, void , void , void , void >{ ... }; template <typename _Category, typename _Tp, typename _Distance = ptrdiff_t , typename _Pointer = _Tp*, typename _Reference = _Tp&> struct iterator{ typedef _Category iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typedef _Pointer pointer; typedef _Reference reference; };
迭代器分类(category)对算法的影响 iterator_category 对算法的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <class InputIterator >inline iterator_traits<InputIterator>::difference_type __distance(InputIterator first, InputIterator last, input_iterator_tag) { iterator_traits<InputIterator>::difference_type n = 0 ; while (first != last) { ++first; ++n; } return n; } template <class RandomAccessIterator >inline iterator_traits<RandomAccessIterator>::difference_type __distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag) { return last - first; } template <class InputIterator >inline iterator_traits<InputIterator>::difference_type distance (InputIterator first, InputIterator last) { typedef typename iterator_traits<InputIterator>::iterator_category category; return __distance(first, last, category ()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 template <class InputIterator , class Distance >inline void __advance(InputIterator& i, Distance n, input_iterator_tag) { while (n--) ++i; } template <class BidirectionalIterator , class Distance >inline void __advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag) { if (n>=0 ) while (n--) ++i; else while (n++) --i; } template <class RandomAccessIterator , class Distance >inline void __advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag) { i += n; } template <class InputIterator , class Distance >inline void advance (InputIterator& i, Distance n) { __advance(i, n, iterator_category (i)); } template <class Iterator >inline typename iterator_traits<Iterator>::iterator_category iterator_category (const Iterator&) { typedef typename iterator_traits<Iterator>::iterator_category category; return category (); }
iterator_category 和 tyoe traits 对算法的影响 has trivial op=() 不重要的拷贝赋值/系统自带的/浅拷贝 has non-trivial op=() 重要的拷贝赋值/深拷贝 Type Traits 问拷贝复制重不重要,Type Traits 不属于 STL 一部分,但是属于标准库一部分
<style>.qjoiikyokhqn{zoom:67%;}</style>{% asset_img qjoiikyokhqn image-20250928235508712.png '"""image-20250928235508712"' %}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 template <class InputIterator , class OutputIterator >inline OutputIterator __unique_copy(InputIterator first, InputIterator last, OutputIterator result, output_iterator_tag) { return __unique_copy(first, last, result, value_type (first)); } template <class Itr >inline typename iterator_traits<Itr>::value_type* value_type (const Itr&) { return static_cast <typename iterator_traits<Itr>::value_type*>(0 ); } template <class InputIterator , class OutputIterator , class T >OutputIterator __unique_copy(InputIterator first, InputIterator last, OutputIterator result, T*) { T value = *first; *result = value; while (++first != last) if (value != *first) { value = *first; *++result = value; } return ++result; } template <class InputIterator , class ForwardIterator >ForwardIterator __unique_copy(InputIterator first, InputIterator last, ForwardIterator result, forward_iterator_tag) { *result = *first; while (++first != last) if (*result != *first) { *++result = *first; } return ++result; }
算法源码中对 iterator_category 的 “暗示” 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <class InputIterator > inline iterator_traits<InputIterator>::difference_type distance (InputIterator first, InputIterator last) { ... } template <class ForwardIterator >inline void rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last) { ... } template <class RandomAccessIterator >inline void sort (RandomAccessIterator first, RandomAccessIterator last) { ... } template <class InputIterator , class T >InputIterator find (InputIterator first, InputIterator last, const T& value) { ... } template <class BidirectionalIterator , class OutputIterator >OutputIterator reverse_copy (BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) { ... }
算法源代码剖析(11个例子) 先前示例中出现的算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { qsort (c.data (), ASIZE, sizeof (long ), compareLongs); long * pItem = (long *)bsearch (&target, (c.data ()), ASIZE, sizeof (long ), compareLongs); } { cout << count_if (vi.begin (), vi.end (), not1 (bind2nd (less <int >(),40 ))); auto ite = find (c.begin (), c.end (), target); sort (c.begin (), c.end ()); } template <typename Iterator>std::Algorithm (Iterator itr1, Iterator itr2, ...) { ... }
算法 accumulate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <class InputIterator , class T >T accumulate (InputIterator first, InputIterator last, T init) { for ( ; first != last; ++first) init = init + *first; return init; } template <class InputIterator , class T , class BinaryOperation >T accumulate (InputIterator first, InputIterator last, T init, BinaryOperation binary_op) { for ( ; first != last; ++first) init = binary_op (init, *first); return init; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> #include <functional> #include <numeric> namespace star34{ int myfunc (int x, int y) { return x+2 *y; } struct myclass { int operator () (int x, int y) { return x+3 *y; } }myobj; void test_accumulate () { int init = 100 ; int nums[] = {10 , 20 , 30 }; cout << "using default accumulate: " ; cout << accumulate (nums, nums+3 , init); cout << '\n' ; cout << "using functional's minus: " ; cout << accumulate (nums, nums+3 , init, minus <int >()); cout << '\n' ; cout << "using custom function: " ; cout << accumulate (nums, nums+3 , init, myfunc); cout << '\n' ; cout << "using custom object: " ; cout << accumulate (nums, nums+3 , init, myobj); cout << '\n' ; } }
算法 for_each 1 2 3 4 5 6 7 template <class InputIterator , class Function >Function for_each (InputIterator first, InputIterator last, Function f) { for ( ; first != last; ++first) f (*first); return f; }
1 2 3 4 5 6 7 for ( decl : coll) { statement } for ( int i : {2 , 3 , 5 , 7 , 9 , 13 , 17 , 19 } ) { cout << i << endl; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <algorithm> #include <vector> namespace star35{ void myfunc (int i) { cout << ' ' << i; } struct myclass { void operator () (int i) { cout << ' ' << i; } }myobj; void test_for_each () { vector<int > myvec; myvec.push_back (10 ); myvec.push_back (20 ); myvec.push_back (30 ); for_each(myvec.begin (), myvec.end (), myfunc); cout << endl; for_each(myvec.begin (), myvec.end (), myobj); cout << endl; for (auto & elem : myvec) elem += 5 ; for (auto elem : myvec) cout << ' ' << elem; } }
算法 replace, replace_if, replace_copy 1 2 3 4 5 6 7 template <class ForwardIterator , class T >void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) { for ( ; first != last; ++first) if (*first == old_value) *first = new_value; }
1 2 3 4 5 6 7 template <class ForwardIterator , class Predicate , class T >void replace_if (ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value) { for ( ; first != last; ++first) if (pred (*first)) *first = new_value; }
1 2 3 4 5 6 7 8 9 10 11 template <class InputIterator , class OutputIterator , class T >OutputIterator replace_copy (InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) { for ( ; first != last; ++first, ++result) *result = *first==old_value ? new_value : *first; return result; }
算法 count, count_if 容器不带 成员函数 count():array, vector, list, forward_list, deque 容器带有 成员函数 count():set/multiset, map/multimap, unordered_set/unordered_multiset, unordered_map/unordered_multimap 容器有自己函数版本时,一定调用自己的,速度更快
1 2 3 4 5 6 7 8 9 10 template <class InputIterator , class T >typename iterator_traits<InputIterator>::difference_type count (InputIterator first, InputIterator last, const T& value) { typename iterator_traits<InputIterator>::difference_type n = 0 ; for ( ; first != last; ++first) if (*first==value) ++n; return n; }
1 2 3 4 5 6 7 8 9 10 template <class InputIterator , class Predicate >typename iterator_traits<InputIterator>::difference_type count_if (InputIterator first, InputIterator last, Predicate pred) { typename iterator_traits<InputIterator>::difference_type n = 0 ; for ( ; first != last; ++first) if (pred (*first)) ++n; return n; }
算法 find, find_if 容器不带 成员函数 find():array, vector, list, forward_list, deque 容器带有 成员函数 find():set/multiset, map/multimap, unordered_set/unordered_multiset, unordered_map/unordered_multimap 容器有自己函数版本时,一定调用自己的,速度更快
1 2 3 4 5 6 7 template <class InputIterator , class T >InputIterator find (InputIterator first, InputIterator last, const T& value) { while (first != last && *first != value) ++first; return first; }
1 2 3 4 5 6 7 template <class InputIterator , class Predicate >InputIterator find_if (InputIterator first, InputIterator last, Predicate pred) { while (first != last && !pred (*first)) ++first; return first; }
算法 sort 容器不带 成员函数 sort():array, vector, deque set/multiset, map/multimap, unordered_set/unordered_multiset, unordered_map/unordered_multimap 遍历自然形成 sorted 状态 容器带有 成员函数 sort():list, forward_list sort函数要求容器迭代器是随机访问迭代器 容器有自己函数版本时,一定调用自己的,速度更快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 bool myfunc (int i,int j) { return (i<j); } struct myclass { bool operator () (int i,int j) { return (i<j); } }myobj; bool test_sort () { int myints[] = {32 , 71 , 12 , 45 , 26 , 80 , 53 , 33 }; vector<int > myvec (myints, myints+8 ) ; sort (myvec.begin (), myvec.begin ()+4 ); sort (myvec.begin ()+4 , myvec.end (), myfunc); sort (myvec.begin (), myvec.end (), myobj); cout << "myvec contains:" ; for (auto elem : myvec) cout << ' ' << elem; sort (myvec.rbegin (), myvec.rend ()); cout << "myvec contains:" ; for (auto elem : myvec) cout << ' ' << elem; }
关于 reverse iterator, rbegin(), rend()
1 2 3 4 5 6 7 8 reverse_iterator rbegin () { return reverse_iterator (end ()); } reverse_iterator rend () { return reverse_iterator (begin ()); }
算法 binary_search Test if value exists in sorted sequence binary_search函数使用前一定要排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 template <class ForwardIterator , class T >bool binary_search (ForwardIterator first, ForwardIterator last, const T& val) { first = std::lower_bound (first, last, val); return (first!=last && !(val < *first)); } template <class ForwardIterator , class T >ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val) { ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = distance (first, last); while (count>0 ) { it = first; step = count/2 ; advance (it,step); if (*it<val) { first = ++ it; count -= step+1 ; } else count=step; } return first; }
仿函数和函数对象 仿函数 functors 1 2 3 4 5 template <typename Iterator, typename Cmp> Algorithm (Iterator itr1, Iterator itr2, Cmp comp){ ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <class T >struct pluc : public binary_function<T, T, T> { T operator () (const T& x, const T& y) const { return x + y; } }; template <class T >struct minus : public binary_function<T, T, T> { T operator () (const T& x, const T& y) const { return x - y; } }; ...
1 2 3 4 5 6 7 8 template <class T >struct logical_and : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x && y; } }; ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <class T >struct equal_to : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x == y; } }; template <class T >struct less : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x < y; } }; ...
1 2 3 4 5 6 7 8 9 10 template <class T1 , class T2 >struct pair { typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair () : first (T1 ()), second (T2 ()) {} pair (const T1& a, const T2& b) : first (a), second (b) {} };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 template <class T >struct identity : public unary_function<T, T> { const T& operator () (const T& x) const { return x; } }; template <class Pair >struct select1st : public unary_function<Pair, typename Pair::first_type> { const typename Pair::first_type& operator () (const Pair& x) const { return x.first; } }; template <class Pair >struct select2nd : public unary_function<Pair, typename Pair::second_type> { const typename Pair::second_type& operator () (const Pair& x) const { return x.second; } }; template <class T >struct _Identity ;template <class Pair >struct _Select1st ;template <class Pair >struct _Select2nd ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 struct myclass { bool operator () (int i, int j) { return ( i<j ); } }myobj; bool myfunc (int i, int j) { return ( i<j ); }template <class T >struct greater : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x > y; } }; template <class T >struct less : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x < y; } }; ... sort (myvec.begin (), myvec.end ()); sort (myvec.begin (), myvec.end (), myfunc); sort (myvec.begin (), myvec.end (), myobj);sort (myvec.begin (), myvec.end (), less <int >()); sort (myvec.begin (), myvec.end (), greater <int >());
仿函数 functors 的可适配(adaptable) 条件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <class Arg , class Result >struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1 , class Arg2 , class Result >struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; template <class T >struct less : public binary_function<T, T, bool > { bool operator () (const T& x, const T& y) const { return x < y; } }; typedef int first_argument_type;typedef int second_argument_type;typedef bool result_type;
存在多种 Adapter adapter改造某个东西,A把B改造之后,A就代表了B,A就被使用,不会再用到B,而A做的主要事情是交给B做,A内含B而不是继承
容器适配器 容器适配器:stack 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <class T , class Sequence =deque<T>>class stack { ... public : typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_reference const_reference; protected : Sequence c; public : bool empty () const { return c.empty (); } size_type size () const { return c.size (); } reference top () { return c.back (); } const_reference top () const { return c.back (); } void push (const value_type& x) { c.push_back (x); } void pop () { c.pop_back (); } };
容器适配器:queue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <class T , class Sequence =deque<T>>class queue { ... public : typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_reference const_reference; protected : Sequence c; public : bool empty () const { return c.empty (); } size_type size () const { return c.size (); } reference front () { return c.front (); } const_reference front () const { return c.front (); } reference back () { return c.back (); } const_reference back () const { return c.back (); } void push (const value_type& x) { c.push_back (x); } void pop () { c.pop_front (); } };
函数适配器 函数适配器:binder2nd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 template <class Operation , class T >inline binder2nd<Operation> bind2nd (const Operation& op, const T& x) { typedef typename Operation::second_argument_type arg2_type; return binder2nd <Operation>(op, arg2_type (x)); } template <class Operation > class binder2nd : public unary_function<typename Operation::first_argument_type, typename Operation::result_type> { protected : Operation op; typename Operation::second_argument_type value; public : binder2nd (const Operation& x, const typename Operation::second_argument_type& y) : op (x), value (y) {} typename Operation::result_type operator () (const typename Operation::first_argument_type& x) const { return op (x, value); } }; template <class InputIterator , class Predicate >typename iterator_traits<InputIterator>::difference_type count_if (InputIterator first, InputIterator last, Predicate pred) { typename iterator_traits<InputIterator>::difference_type n = 0 ; for ( ; first != last; ++first) if (pred (*first)) ++n; return n; }
函数适配器:not1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <class Predicate >inline unary_negate<Predicate> not1 (const Predicate& pred) { return unary_negate <Predicate>(pred); } template <class Predicate >class unary_negate : public unary_function<typename Predicate::argument_type, bool > { protected : Predicate pred; public : explicit unary_negate (const Predicate& x) : pred(x) { } bool operator () (const typename Predicate::argument_type& x) const { return !pred (x); } }; template <class InputIterator , class Predicate >typename iterator_traits<InputIterator>::difference_type count_if (InputIterator first, InputIterator last, Predicate pred) { typename iterator_traits<InputIterator>::difference_type n = 0 ; for ( ; first != last; ++first) if (pred (*first)) ++n; return n; }
新型适配器,bind Since C++11 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
std::bind 可以绑定:
functions
function objects
member functions,_1 必须是某个 object 地址 _1 是一个占位符号,代表符号
data members,_1 必须是某个 object 地址
返回一个 function object ret 调用 ret 相当于调用上述 1, 2, 3,或相当于取出 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <functional> double my_divide (double x, double y) { return x / y; } struct MyPair { double a,b; double multiply () { return a * b; } }; using namespace std::placeholders; auto fn_five = bind (my_divide, 10 , 2 ); cout << fn_five () << '\n' ; auto fn_half = bind (my_divide, _1, 2 ); cout << fn_half (10 ) << '\n' ; auto fn_invert = bind (my_divide, _2, _1); cout << fn_invert (10 , 2 ) << '\n' ; auto fn_rounding = bind <int >(my_divide, _1, _2); cout << fn_rounding (10 , 3 ) << '\n' ; MyPair ten_two{10 , 2 }; auto bound_memfn = bind (&MyPair::multiply, _1); cout << bound_memfn (ten_two) << '\n' ; auto bound_memdata = bind (&MyPair::a, ten_two); cout << bound_memdata () << '\n' ; auto bound_memdata2 = bind (&MyPair::b, _1); cout << bound_memdata2 (ten_two) << '\n' ; vector<int > v{15 , 37 , 94 , 50 , 73 , 58 , 28 , 98 }; int n = count_if (v.begin (), v.end (), not1 (bind2nd (less <int >(), 50 )));cout << "n= " << n << endl; auto fn_ = bind (less <int >(), _1, 50 );cout << count_if (v.cbegin (), v.cend (), fn_) << endl; cout << count_if (v.begin (), v.end (), bind (less <int >(), _1, 50 )) << endl;
迭代器适配器 迭代器适配器:reverse_iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 reverse_iterator rbegin () { return reverse_iterator (end ()); } reverse_iterator rend () { return reverse_iterator (begin ()); } template <class Iterator >class reverse_iterator { protected : Iterator current; public : typedef typename iterator_traits<Iterator>::iterator_category iterator_category; typedef typename iterator_traits<Iterator>::value_type value_type; ... typedef Iterator iterator_type; typedef reverse_iterator<Iterator> self; public : explicit reverse_iterator (iterator_type x) : current(x) { } reverse_iterator (const self& x) : current (x.current) {} iterator_type base () const { return current; } reference operator *() const { Iterator tmp = current; return *--tmp; } pointer operator ->() const { return &(operator *()); } self& operator ++() { --current; return *this ; } self& operator --() { ++current; return *this ; } self& operator +(difference_type n) const { return self (current - n); } self& operator -(difference_type n) const { return self (current + n); } };
迭代器适配器:inserter 1 2 3 4 5 6 7 8 9 10 template <class InputIterator , class OutputIterator >OutputIterator copy (InputIterator first, InputIterator last, OurputIterator result) { while (first != last) { *result = *first; ++result; ++first; } return result; }
1 2 3 4 int myints[]={10 , 20 , 30 , 40 , 50 , 60 , 70 };vector<int > myvec (7 ) ;copy (myints, myints+7 , myvec.begin ());
1 2 3 4 5 6 7 8 9 10 11 list<int > foo, bar; for (int i=1 ; i<=5 ; i++){ foo.push_back (i); bar.push_back (i*10 ); } list<int >::iterator it = foo.begin (); advance (it, 3 );copy (bar.begin (), bar.end (), inserter (foo, it));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <class Container , class Iterator >inline insert_iterator<Container> inserter (Container& x, Iterator i) { typedef typename Container::iterator iter; return insert_iterator <Container>(x, iter (i)); } template <class Container >class insert_iterator { protected : Container* container; typename Container::iterator iter; public : typedef output_iterator_tag iterator_category; insert_iterator (Container& x, typename Container::iterator i) : container (&x), iter (i) {} insert_iterator<Container>& operator =(const typename Container::value_type& value) { iter = container->insert (iter, value); ++iter; return *this ; } };
X(未知)适配器 X(未知)适配器:ostream_iterator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream> #include <iterator> #include <vector> #include <algorithm> int main () { std::vector<int > myvector; for (int i=1 ; i<10 ; ++i) myvector.push_back (i*10 ); std::ostream_iterator<int > out_it (std::cout, "," ) ; std::copy (myvector.begin (), myvector.end (), out_it); return 0 ; } template <class InputIterator , class OutputIterator > OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) { while (first != last) { *result = *first; ++result; ++first; } return result; } template <class T , class charT =char , class traits=char_traits<charT> >class ostream_iterator : public iterator<output_iterator_tag, void , void , void , void >{ basic_ostream<charT, traits>* out_stream; const charT* delim; public : typedef charT char_type; typedef traits traits_type; typedef basic_ostream<charT, traits> ostream_type; ostream_iterator (ostream_type& s) : out_stream (&s), delim (0 ) {} ostream_iterator (ostream_type& s, const charT* delimiter) : out_stream (&s), delim (delimiter) { } ostream_iterator (const ostream_iterator<T, charT, traits>& x) : out_stream (x.out_stream), delim (x.delim) {} ~ostream_iterator () {} ostream_iterator<T, charT, traits>& operator =(const T& value) { *out_stream << value; if (delim!=0 ) *out_stream << delim; return *this ; } ostream_iterator<T, charT, traits>& operator *() { return *this ; } ostream_iterator<T, charT, traits>& operator ++() { return *this ; } ostream_iterator<T, charT, traits>& operator ++(int ) { return *this ; } };
X(未知)适配器:istream_iterator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <class T , class charT =char , class traits=char_traits<charT>, class Distance=ptrdiff_t >class istream_iterator : public iterator<input_iterator_tag, T, Distance, const T*, const T&>{ basic_istream<charT, traits>* in_stream; T value; public : typedef charT char_type; typedef traits traits_type; typedef basic_istream<charT, traits> istream_type; istream_iterator () : in_stream (0 ) {} istream_iterator (istream_type& s) : in_stream (&s) { ++*this ; } istream_iterator (const istream_iterator<T, charT, traits, Distance>& x) : in_stream (x.in_stream), value (x.value) {} ~istream_iterator () {} const T& operator *() const { return value; } const T* operator ->() const { return &value; } istream_iterator<T, charT, traits, Distance>& operator ++() { if (in_stream && !(*in_stream >> value)) in_stream=0 ; return *this ; } istream_iterator<T, charT, traits, Distance> operator ++(int ) { istream_iterator<T, charT, traits, Distance> tmp = *this ; ++*this ; return tmp; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <iterator> int main () { double value1, value2; std::cout << "Please, insert two values: " ; std::istream_iterator<double > eos; std::istream_iterator<double > iit (std::cin) ; if (iit!=eos) value1=*iit; ++iit; if (iit!=eos) value2=*iit; std::cout << value1 << "*" << value2 << "=" << (value1*value2) << '\n' ; return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <class InputIterator , class OutputIterator >OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) { while (first != last) { *result = *first; ++result; ++first; } return result; } { istream_iterator<int > iit (cin) , eos ; copy (iit, eos, inserter (c, c.begin ())); }
阅读 C++ 标准库源代码——意义与价值 使用一个东西,却不明白它的道理,不高明!
一个万用的 hash function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <functional> class Customer { ... }; class CustomerHash { public : std::size_t operator () (const Customer& c) const { return ... } }; unordered_set<Customer, CustomerHash> custset;
1 2 3 4 5 6 size_t customer_hash_func (const Customer& c) { return ... }; unordered_set<Customer, size_t (*) (const Customer&) > custset (20 , customer_hash_func) ;
1 2 3 4 5 6 7 8 class CustomerHash { public : std::size_t operator () (const Customer& c) const { return std::hash <std::string>()(c.fname) + std::hash <std::string>()(c.lname) + std::hash <long >()(c.no); } };
using variadic templates allows calling hash_val () with an arbitrary number of elements of any type to process a hash value out of all these values
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include <functional> template <typename T>inline void hash_combine (size_t & seed, const T& val) { seed ^= std::hash <T>()(val) + 0x9e3779b9 + (seed<<6 ) + (seed>>2 ); } template <typename T>inline void hash_val (size_t & seed, const T& val) { hash_combine (seed, val); } template <typename T, typename ... Types>inline void hash_val (size_t & seed, const T& val, const Types&... args) { hash_combine (seed, val); hash_val (seed, args...); } template <typename ... Types>inline size_t hash_val (const Types&... args) { size_t seed = 0 ; hash_val (seed, args...); return seed; } class CustomerHash { public : std::size_t operator () (const Customer& c) const { return hash_val (c.fname, c.lname, c.no); } }; { unordered_set<Customer, CustomerHash> set3; set3. insert ( Customer ("Ace" , "Hou" , 1L ) ); set3. insert ( Customer ("Sabri" , "Hou" , 2L ) ); set3. insert ( Customer ("Stacy" , "Chen" , 3L ) ); set3. insert ( Customer ("Mike" , "Tseng" , 4L ) ); set3. insert ( Customer ("Paili" , "Chen" , 5L ) ); set3. insert ( Customer ("Light" , "Shiau" , 6L ) ); set3. insert ( Customer ("Shally" , "Hwung" , 7L ) ); cout << "set3 current bucket_count: " << set3. bucket_count () << endl; CustomerHash hh; cout << "bucket position of Ace = " << hh (Customer ("Ace" , "Hou" , 1L )) % 11 << endl; cout << "bucket position of Sabri = " << hh (Customer ("Sabri" , "Hou" , 2L )) % 11 << endl; cout << "bucket position of Stacy = " << hh (Customer ("Stacy" , "Chen" , 3L )) % 11 << endl; cout << "bucket position of Mike = " << hh (Customer ("Mike" , "Tseng" , 4L )) % 11 << endl; cout << "bucket position of Paili = " << hh (Customer ("Paili" , "Chen" , 5L )) % 11 << endl; cout << "bucket position of Light = " << hh (Customer ("Light" , "Shiau" , 6L )) % 11 << endl; cout << "bucket position of Shally = " << hh (Customer ("Shally" , "Hwung" , 7L )) % 11 << endl; for (unsigned i=0 ; i<set3. bucket_count (); ++i) { cout << "bucket #" << i << " has " << set3. bucket_size (i) << " elements.\n" ; } }
以 struct hash 偏特化 形式 实现 Hash Function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T> >class unordered_set;template <typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T> >class unordered_multiset;template <typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<const Key, T> > > class unordered_map;template <typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<const Key, T> > > class unordered_multimap;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class MyString { private : char * _data; size_t _len; ... }; namespace std { template <> struct hash <MyString> { size_t operator () (const MyString& s) const noexcept { return hash <string>()(string (s.get ())); } }; }
1 2 3 4 5 6 7 8 9 10 template <>struct hash <string> : public __hash_base<size_t , string>{ size_t operator () (const string& __s) const noexcept { return std::_Hash_impl::hash (__s.data (), __s.length ()); } };
Tuple tuple, 用例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 cout << "string, sizeof= " << sizeof (string) << endl; cout << "double, sizeof= " << sizeof (double ) << endl; cout << "float, sizeof= " << sizeof (float ) << endl; cout << "int, sizeof= " << sizeof (int ) << endl; cout << "complex<double>, sizeof=" << sizeof (complex<double >) << endl; tuple<string, int , int , complex<double >> t; cout << "sizeof= " << sizeof (t) << endl; tuple<int , float , string> t1 (41 , 6.3 , "nico" ) ;cout << "tuple<int, float, string>, sizeof= " << sizeof (t1) << endl; cout << "t1: " << get <0 >(t1) << ' ' << get <1 >(t1) << ' ' << get <2 >(t1) << endl; auto t2 = make_tuple (22 , 44 , "stacy" ); get <1 >(t1) = get <1 >(t2);if (t1 < t2) { cout << "t1 < t2" << endl; } else { cout << "t1 >= t2" << endl; } t1 = t2; cout << "t1: " << t1 << endl; tuple<int , float , string> t3 (77 , 1.1 , "more light" ) ;int i1;float f1;string s1; tie (i1, f1, s1) = t3; typedef tuple<int , float , string> TupleType;cout << tuple_size<TupleType>::value << endl; tuple_element<1 , TupleType>::type f1; typedef tuple_element<1 , TupleType>::type T;
tuple 元之组合,数之组合 详细介绍见 C++2.0新特性C++2.0新特性 | tiny_star_blog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <typename ... Values> class tuple ;template <> class tuple <> {};template <typename Head, typename ... Tail>class tuple <Head, Tail...> : private tuple<Tail...>{ typedef tuple<Tail...> inherited; public : tuple () {} tuple (Head v, Tail... vtail) : m_head (v), inherited (vtail...) {} typename Head::type head () { return m_head; } inherited& tail () { return *this ; } protected : Head m_head; }; { tuple<int , float , string> t (41 , 6.3 , "nico" ) ; t.head (); t.tail (); t.tail ().head (); &(t.tail ()); }
type traits 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 struct __true_type { };struct __false_type { };template <class type >struct __type_traits { typedef __true_type this_dummy_member_must_be_first; typedef __false_type has_trivial_default_constructor; typedef __false_type has_trivial_copy_constructor; typedef __false_type has_trivial_assignment_operator; typedef __false_type has_trivial_destructor; typedef __false_type is_POD_type; }; template <> struct __type_traits <int > { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; template <> struct __type_traits <double > { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; __type_traits<Foo>::has_trivial_destructor
Since C++11 cplusplus.com/reference/type_traits/?kw=type_traits 自建类型不需要写特化版本
Primary type categories
is_array
Is array (class template)
is_class
Is non-union class (class template)
is_enum
Is enum (class template)
is_floating_point
Is floating point (class template)
is_function
Is function (class template)
is_integral
Is integral (class template)
is_lvalue_reference
Is lvalue reference (class template)
is_member_function_pointer
Is member function pointer (class template)
is_member_object_pointer
Is member object pointer (class template)
is_pointer
Is pointer (class template)
is_rvalue_reference
Is rvalue reference (class template)
is_union
Is union (class template)
is_void
Is void (class template)
Composite type categories
is_arithmetic
Is arithmetic type (class template)
is_compound
Is compound type (class template)
is_fundamental
Is fundamental type (class template)
is_member_pointer
Is member pointer type (class template)
is_object
Is object type (class template)
is_reference
Is reference type (class template)
is_scalar
Is scalar type (class template)
Type properties
is_abstract
Is abstract class (class template)
is_const
Is const-qualified (class template)
is_empty
Is empty class (class template)
is_literal_type
Is literal type (class template)
is_pod
Is POD type (class template)
is_polymorphic
Is polymorphic (class template)
is_signed
Is signed type (class template)
is_standard_layout
Is standard-layout type (class template)
is_trivial
Is trivial type (class template)
is_trivially_copyable
Is trivially copyable (class template)
is_unsigned
Is unsigned type (class template)
is_volatile
Is volatile-qualified (class template)
Type features
has_virtual_destructor
Has virtual destructor (class template)
is_assignable
Is assignable (class template)
is_constructible
Is constructible (class template)
is_copy_assignable
Is copy assignable (class template)
is_copy_constructible
Is copy constructible (class template)
is_destructible
Is destructible (class template)
is_default_constructible
Is default constructible (class template)
is_move_assignable
Is move assignable (class template)
is_move_constructible
Is move constructible (class template)
is_trivially_assignable
Is trivially assignable (class template)
is_trivially_constructible
Is trivially constructible (class template)
is_trivially_copy_assignable
Is trivially copy assignable (class template)
is_trivially_copy_constructible
Is trivially copy constructible (class template)
is_trivially_destructible
Is trivially destructible (class template)
is_trivially_default_constructible
Is trivially default constructible (class template)
is_trivially_move_assignable
Is trivially move assignable (class template)
is_trivially_move_constructible
Is trivially move constructible (class template)
is_nothrow_assignable
Is assignable throwing no exceptions (class template)
is_nothrow_constructible
Is constructible throwing no exceptions (class template)
is_nothrow_copy_assignable
Is copy assignable throwing no exceptions (class template)
is_nothrow_copy_constructible
Is copy constructible throwing no exceptions (class template)
is_nothrow_destructible
Is nothrow destructible (class template)
is_nothrow_default_constructible
Is default constructible throwing no exceptions (class template)
is_nothrow_move_assignable
Is move assignable throwing no exception (class template)
is_nothrow_move_constructible
Is move constructible throwing no exceptions (class template)
trivial 琐碎的,平凡的,平淡无奇的,无关痛痒的,无价值的,不重要的
type traits,测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <typename T>void type_traits_output (const T& x) { cout << "\ntype traits for type : " << typeid (T).name () << endl; cout << "is_void\t" << is_void<T>::value << endl; cout << "is_integral\t" << is_integral<T>::value << endl; cout << "is_floating_point\t" << is_floating_point<T>::value << endl; cout << "is_arithmetic\t" << is_arithmetic<T>::value << endl; cout << "is_signed\t" << is_signed<T>::value << endl; cout << "is_unsigned\t" << is_unsigned<T>::value << endl; cout << "is_const\t" << is_const<T>::value << endl; cout << "is_volatile\t" << is_volatile<T>::value << endl; cout << "is_class\t" << is_class<T>::value << endl; cout << "is_function\t" << is_function<T>::value << endl; cout << "is_reference\t" << is_reference<T>::value << endl; cout << "is_lvalue_reference\t" << is_lvalue_reference<T>::value << endl; cout << "is_rvalue_reference\t" << is_rvalue_reference<T>::value << endl; cout << "is_pointer\t" << is_pointer<T>::value << endl; cout << "is_member_pointer\t" << is_member_pointer<T>::value << endl; cout << "is_member_object_pointer\t" << is_member_object_pointer::value << endl; cout << "is_member_function_pointer\t" << is_member_function_pointer::value << endl; cout << "is_fundamental\t" << is_fundamental<T>::value << endl; cout << "is_scalar\t" << is_scalar<T>::value << endl; cout << "is_object\t" << is_object<T>::value << endl; cout << "is_compound\t" << is_compound<T>::value << endl; ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 typedef basic_string<char > string;typedef basic_string<wchar_t > wstring;typedef basic_string<char16_t > u16string;typedef basic_string<char32_t > u32string;template <typename _CharT, typename _Traits, typename _Alloc>class basic_string { ... basic_string (const basic_string& __str); basic_string (basic_string&& __str) #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 noexcept #endif : _M_dataplus(__str._M_dataplus) { ... } ~basic_string () _GLIBCXX_NOEXCEPT { _M_rep()->_M_dispose(this ->get_allocator ()); } basic_string& operator =(const basic_string& __str) { return this ->assign (__str); } operator =(basic_string&& __str) { this ->swap (__str); return *this ; } ... };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Foo { private : int d1, d2; }; type_traits_output (Foo ());
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Goo { public : virtual ~Goo () { } private : int d1, d2; }; type_traits_output (Goo ());
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class Zoo { public : Zoo (int i1, int i2) : d1 (i1), d2 (i2) { } Zoo (const Zoo&) = delete ; Zoo (Zoo&&) = default ; Zoo& operator =(const Zoo&) = default ; Zoo& operator =(const Zoo&&) = delete ; virtual ~Zoo () { } private : int d1, d2; }; type_traits_output (Zoo (1 , 2 ));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 type_traits_output (complex <float >());
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 type_traits_output<list <int >());
type traits, 实现, is_void 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 template <typename _Tp>struct remove_const { typedef _Tp type; }; template <typename _Tp>struct remove_const <_Tp const > { typedef _TP type; }; template <typename _Tp>struct remove_volatile { typedef _Tp type; }; template <typename _Tp>struct remove_volatile <_Tp volatile >{ typedef _Tp type; }; template <typename _Tp>struct remove_cv { typedef typename remove_const<typename remove_volatile<_Tp>::type>::type type; }; template <typename _Tp>struct add_const { typedef _Tp const type; };
1 2 3 4 5 6 template <typename > struct __is_void_helper : public false_type { };template <> struct __is_void_helper <void > : public true_type { };template <typename _Tp> struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type { };
type traits, 实现 is_integral 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 template <typename >struct __is_integral_helper : public false_type { };template <>struct __is_integral_helper <bool > : public true_type { };template <>struct __is_integral_helper <char > : public true_type { };template <>struct __is_integral_helper <signed char > : public true_type { };template <>struct __is_integral_helper <unsigned char > : public true_type { };... template <>struct __is_integral_helper <int > : public true_type { };template <>struct __is_integral_helper <unsigned int > : public true_type { };template <>struct __is_integral_helper <long > : public true_type { };template <>struct __is_integral_helper <unsigned long > : public true_type { };template <>struct __is_integral_helper <long long > : public true_type { };template <>struct __is_integral_helper <unsigned long long > : public true_type { };... template <typename _Tp>struct is_integral : public __is_integral_helper<typename remove_cv<_Tp>::type>::type { };
type traits, 实现 is_class, is_union, is_enum, is_pod 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <typename _Tp>struct is_enum : public integral_constant<bool , __is_enum(_Tp)> { };template <typename _Tp>struct is_union : public integral_constant<bool , __is_union(_Tp)> { };template <typename _Tp>struct is_class : public integral_constant<bool , __is_class(_Tp)> { };template <typename _Tp>struct is_pod : public integral_constant<bool , __is_pod(_Tp)> { };
__is_enum() __is_union() __is_class() __is_pod() 这些 _is_xxx 未曾出现于 C++ 标准库源代码,可能是编译器实现
type traits, 实现 is_move_assignable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <typename _Tp>struct __is_referenceable : public __or_<is_object<_Tp>, is_reference<_Tp>>::type { };template <typename _Res, typename ... _Args>struct __is_referenceable <_Res(_Args...)> : public true_type { };template <typename _Res, typename ... _Args>struct __is_referenceable <_Res(_Args......)> : public true_type { };... template <typename _Tp, bool = __is_referenceable<_Tp>::value>struct __is_move_assignable_impl;template <typename _Tp>struct __is_move_assignable_impl <_Tp, false > : public false_type { };template <typename _Tp>struct __is_move_assignable_impl <_Tp, true > : public is_assignable<_Tp&, _Tp&&> { };template <typename _Tp>struct is_move_assignable : public __is_move_assignable_impl<_Tp> { };
__is_referenceable() 未曾出现于 C++ 标准库源代码,可能是编译器实现
cout 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class ostream : virtual public ios{ public : ostream& operator <<(char c); ostream& operator <<(unsigned char c) { return (*this ) << (char )c; } ostream& operator <<(signed char c) { return (*this ) << (char )c; } ostream& operator <<(const char *s); ostream& operator <<(const unsigned char *s) { return (*this ) << (const char *)s; } ostream& operator <<(const signed char *s) { return (*this ) << (const char *)s; } ostream& operator <<(const void *p); ostream& operator <<(int n); ostream& operator <<(unsigned int n); ostream& operator <<(long n); ostream& operator <<(unsigned long n); ... }; class _IO_ostream_withassign : public ostream { public : _IO_ostream_withassign& operator =(ostream&); _IO_ostream_withassign& operator =(_IO_ostream_withassign& rhs) { return operator =(static_cast <ostream&>(rhs)); } }; extern _IO_ostream_withassign cout;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 template <typename _CharT, typename _Traits, typename _Alloc>inline basic_ostream<_CharT, _Traits>& operator <<(basic_ostream<_CharT, _Traits>& __os, const basic_string<_CharT, _Traits, _Alloc>& __str) { ... } template <typename _Tp, typename _CharT, class _Traits >basic_ostream<_CharT, _Traits>& operator <<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) { ... } template <class _CharT , class _Traits >inline basic_ostream<_CharT, Traits>& operator <<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) { ... } template <typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>inline std::basic_ostream<_Ch, _Tr>& operator <<(std::basic_ostream<_Ch, _Tr>& __os, const __shared_ptr<_Tp, _Lp>& __p) { ... } template <typename _Ch_type, typename _Ch_traits, typename _Bi_iter>inline basic_ostream<_Ch_type, _Ch_traits>& operator <<(basic_ostream<_Ch_type, _Ch_traits>& __os, const sub_match<_Bi_iter>& __m) { ... } template <class _CharT , class _Traits , size_t _Nb>std::basic_ostream<_CharT, _Traits>& operator <<(std::basic_ostream<_CharT, _Traits>& __os, const bitset<_Nb>& __x) { ... }
movable 元素 详细介绍见 C++2.0新特性C++2.0新特性 | tiny_star_blog
1 2 3 4 5 6 7 8 9 10 11 12 13 { M c1; ... M c11 (c1) ; M c12 (std::move(c1)) ; c11. swap (c12); for (long i=0 ; i<value; ++i) { snprintf (buf, 10 , "%d" , rand ()); auto ite = c1. end (); c1. insert (ite, V1type (buf)); } }
movable 元素对于 vector 速度效能的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
movable 元素对于 list 速度效能的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
movable 元素对于 deque 速度效能的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
moveable 元素对于 multiset 速度效能的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
moveable 元素对于 unordered_multiset 速度效能的影响 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
写一个 moveable class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 class MyString { public : static size_t DCtor; static size_t Ctor; static size_t CCtor; static size_t CAsgn; static size_t MCtor; static size_t MAsgn; static size_t Dtor; private : char * _data; size_t _len; void _init_data(const char *s) { _data = new char [_len+1 ]; memcpy (_data, s, _len); _data[_len] = '\0' ; } public : MyString () : _data(NULL ), _len(0 ) { ++DCtor; } MyString (const char * p) : _len(strlen (p)) { ++Ctor; _init_data(p); } MyString (const MyString& str) : _len(str._len) { ++CCtor; _init_data(str._data); } MyString (MyString&& str) noexcept : _data(str._data), _len(str._len) { ++MCtor; str._len = 0 ; str._data = NULL ; } MyString& operator =(const MyString& str) { ++CAsgn; if (this != &str) { if (_data) delete _data; _len = str._len; _init_data(str._data); }else { } return *this ; } MyString& operator =(MyString&& str) noexcept { ++MAsgn; if (this != &str) { if (_data) delete _data; _len = str._len; _data = str._data; str._len = 0 ; str._data = NULL ; } return *this ; } virtual ~MyString () { ++Dtor; if (_data) { delete _data; } } bool operator <(const MyStirng& rhs) const { return std::string (this ->_data) < std::string (rhs._data); } bool operator ==(const MyString& rhs) const { return std::string (this ->_data) == std::string (rhs._data); } char * get () const { return _data; } }; size_t MyString::DCtor=0 ;size_t MyString::Ctor=0 ;size_t MyString::CCtor=0 ;size_t MyString::CAsgn=0 ;size_t MyString::MCtor=0 ;size_t MyString::MAsgn=0 ;size_t MyString::Dtor=0 ;namespace std { template <> struct hash <MyString> { size_t operator () (const MyString& s) const noexcept { return hash <string>()(string (s.get ())); } }; }
测试函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <typeinfo> template <typename T>void output_static_data (const T& myStr) { cout << typeid (myStr).name () << "--" << endl; cout << " CCtor= " << T::CCtor << " MCtor= " << T::MCtor << " CAsgn= " << T::CAsgn << " MAsgn= " << T::MAsgn << " Dtor= " << T::Dtor << " Ctor= " << T::Ctor << " DCtor= " << T::DCtor << endl; } template <typename M, typename NM>void test_moveable (M c1, NM c2, long & value) { char buf[10 ]; typedef typename iterator_traits<typename M::iterator>::value_type V1type; clock_t timeStart = clock (); for (long i=0 ; i<value; ++i) { snprintf (buf, 10 , "%d" , rand ()); auto ite = c1. end (); c1. insert (ite, V1type (buf)); } cout << "construction, milli-seconds: " << (clock ()-timeStart) << endl; cout << "size()= " << c1. size () << endl; output_static_data (*(c1. begin ())); M c11 (c1) ; M c12 (std::move(c1)) ; c11. swap (c12); ... } test_moveable (vector <MyString>(), vector <MyStrNoMove>(), value);
vector 的 copy ctor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 vector (const vector& __x) : _Base(__x.size (), _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())){ this ->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin (), __x.end (), this ->_M_impl._M_start, _M_get_Tp_allocator()); } { M c11 (c1) ; M c12 (std::move(c1)) ; }
vector 的 move ctor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void _M_swap_data(_Vector_impl& __x){ std::swap (_M_start, __x._M_start); std::swap (_M_finish, __x._M_finish); std::swap (_M_end_of_storage, __x._M_end_of_storage); } _Vector_base(_Vector_base&& __x) noexcept : _M_impl(std::move (__x._M_get_Tp_allocator())) { this ->_M_impl._M_swap_data(__x._M_impl); } vector (vector&& __x) noexcept : _Base(std::move (__x)) { }
std::string 是否 moveable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 template <typename _CharT, typename _Traits, typename _Alloc>basic_string<_CharT, _Traits, _Alloc>::basic_string (const basic_string& __str) : _M_dataplus(__str._M_rep()->_M_grab(_Alloc(__str.get_allocator ()), __str.get_allocator ()), __str.get_allocator) { } basic_string (const basic_string& __str);#if __cplusplus >= 201103L basic_string (basic_string&& __str) #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 noexcept #endif : _M_dataplus(__str._M_dataplus) { #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 __str._M_data(_S_empty_rep()._M_refdata()); #else __str._M_data(_S_construct(size_type (), _CharT(), get_allocator ())); #endif } basic_string& operator =(const basic_string& __str) { return this ->assign (__str); } #if __cplusplus >= 201103L basic_string& operator =(basic_string&& __str) { this ->swap (__str); return *this ; }