GeekBand极客班STL与泛型编程第一周笔记

c++标准库体系结构与内核分析

第一讲:示范运用STL各大部件 (components),并初步认识其体系结构

1.认识headers、版本、重要资源

所谓generic programing,GP泛型编程,就是使用template模板为主要工具来编写程序
根据源代码分析c++STL之体系结构
应具备的基础:c++基本语法,包括如何正确使用模板templates
-level0:使用c++标准库
-level1:深入认识c++标准库,清楚其在内存中的结构等
-level2:良好使用c++标准库
-level3:扩充c++标准库
c++标准库与STL
-c++ standard library:目前c++中已给的头文件
-standard template library:标准模板库,分为六大部件,标准库中大量存在STL
-标准库以Header files形式呈现,所以源代码可见
-headers中的组件封装于namespace std
using namespace std;
using std::cout;

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

不同版本标准库的用法基本相同
推荐网站:
-www.cplusplus.com
-en.cppreference.com
-gcc.gnu.org

2.STL体系结构基础介绍

STL六大部件:
-容器containers
-分配器allocators
-算法algorithms
-迭代器iterators
-适配器adapters
-仿函式functors
分配器用来支持容器存放
部分操作在容器本身操作另外部分放在算法操作
面向对象编程中鼓励将数据及函数放在类中,与STL不同
容器用来存放要处理的数据,算法对容器中的数据进行处理
迭代器是数据与操作的桥梁,是一种泛化的指针
仿函数作用像函数一样
适配器用来帮助转换,迭代器适配、仿函数适配、容器适配

#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)));   
//      算法↑ 迭代器↑           适配器↑       
//对数据的操作:需要用适配器来做容器和算法的接口
//predicate
    return 0;
}

复杂度complexity
-O(1)、O(c):常数时间 constant time
-O(n):线性时间 linear time
-O(log2n):次线性实践 sub-linear time
-O(n^2):平方时间 quadratic time
-O(n^3):立方时间 cubic time
-O(2^n):指数时间 exponential time
-O(nlog2n):介于线性及二次方成长的中间
“前闭后开”区间
标准库规定,容器中头指针指向第一个元素,尾指针所指为容器最后元素的下一个位置
容器中的空间并不一定连续,也可能是链表或者哈希表


Container<T> c;
...
Container<T>::iterator ite = c.begin();
//容器都有其专属的一个iterator,用其类型声明头指针
for(;ite!=c.end();ite++)
...
//对容器进行遍历

c++11新功能:
-对容器进行遍历
range-based "for" statement (since C++11)
for(decl:coll){statement}

for(int i : {2,3,5,7,9,13,17,19})
{
    std::cout<<i<<std::endl;
}
std::vector<double> vec;
for(auto elem : vec)
{
    std::cout<<elem<<std::endl;
}
for(auto& elem : vec)
{
    elem *= 3;
}

-auto keyword

list<string> c;
...
list<string>::iterator ite;
ite=::find(c.begin(),c.end(),/*target*/);

list<string> c;
...
auto ite = ::find(c.begin(),c.end(),/*target*/);

3.容器之分类与各种测试

容器-结构

-顺序表
-链表
-树
-堆
-哈希表

容器-分类

sequence containers
associative containers
unordered containers
hash table separate chaining
-array,固定大小,不可扩充
-vector,开头固定,尾可扩充
-list,双链表,双向都有指针
-forward_list,单链表,指针为单向
-slist
-deque,头尾可扩充
-stack
-multiset,集合中元素可重复
-multimap
-unordered_multiset,分散无序存放,
-unordered_multimap
-set,集合,一种平衡二叉树,每个元素中key和value为同一个,集合中元素不可重复
-map,图,通常用红黑树,每个元素中key和value为不同变量
-unordered_set
-unordered_map
-hash_set,哈希结构,目前最优
-hash_multiset
-hash_multimap


四个函数
-输入一个target
-输入一个字符串target
-比较两个long型大小
-比较两个字符串大小

使用容器array

#include <array>
#include <iostream>
#include <ctime> 
#include <cstdlib> //qsort, bsearch, NULL

namespace jj01
{
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;  
}
}

array
-尖括号中第一个参数为类型,第二个参数为容器大小

使用容器vector

#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
#include <algorithm>    //sort()
namespace jj02
{
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;   
                 //曾經最高 i=58389486 then std::bad_alloc
            abort();
        }
    }
    cout << "milli-seconds : " << (clock()-timeStart) << endl;  
    cout << "vector.max_size()= " << c.max_size() << endl;  //1073747823
    cout << "vector.size()= " << c.size() << endl;      
    cout << "vector.front()= " << c.front() << endl;    
    cout << "vector.back()= " << c.back() << endl;  
    cout << "vector.data()= " << c.data() << endl;
    cout << "vector.capacity()= " << c.capacity() << endl << endl;      

                                                                                
string target = get_a_target_string();
    {
    timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
    cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;  
     
    if (pItem != c.end())
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;
    }

    {
    timeStart = clock();
    sort(c.begin(), c.end());
    cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl; 
    
    timeStart = clock();        
string* pItem = (string*)::bsearch(&target, (c.data()), 
                                   c.size(), sizeof(string), compareStrings); 
    cout << "bsearch(), milli-seconds : " << (clock()-timeStart) << endl; 
       
    if (pItem != NULL)
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;  
    }
    
    c.clear();
    test_moveable(vector<MyString>(),vector<MyStrNoMove>(), value); 
}   
}

-tips:测试程序的每一段归在一个namespace中
vector
-尖括号中的参数为类型

使用容器list

#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime> 
namespace jj03
{
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;    //357913941
    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 << "std::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;                
        
    c.clear();
    test_moveable(list<MyString>(),list<MyStrNoMove>(), value);                             
}   
}

list
-尖括号参数为类型
循环存入数据

4.分配器之测试

使用分配器allocator

不同容器在声明时候的分配方式
-尖括号第二位置的参数即是所选用的分配器

#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib>      //abort()
#include <cstdio>       //snprintf()
#include <algorithm>    //find()
#include <iostream>
#include <ctime> 

#include <cstddef>
#include <memory>   //內含 std::allocator  
    //欲使用 std::allocator 以外的 allocator, 得自行 #include <ext\...> 
#ifdef __GNUC__     
#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>  
#endif

namespace jj20
{
//pass A object to function template impl(),
//而 A 本身是個 class template, 帶有 type parameter T,  
//那麼有無可能在 impl() 中抓出 T, 創建一個 list<T, A<T>> object? 
//以下先暫時迴避上述疑問.
    
void test_list_with_special_allocator()
{
#ifdef __GNUC__ 
    cout << "\ntest_list_with_special_allocator().......... \n";
     
    //不能在 switch case 中宣告,只好下面這樣.               //1000000次 
    list<string, allocator<string>> c1;                     //3140
    list<string, __gnu_cxx::malloc_allocator<string>> c2;   //3110
    list<string, __gnu_cxx::new_allocator<string>> c3;      //3156
    list<string, __gnu_cxx::__pool_alloc<string>> c4;       //4922
    list<string, __gnu_cxx::__mt_alloc<string>> c5;         //3297
    list<string, __gnu_cxx::bitmap_allocator<string>> c6;   //4781                                                      
     
int choice;
long value;     

    cout << "select: "
         << " (1) std::allocator "
         << " (2) malloc_allocator "
         << " (3) new_allocator "
         << " (4) __pool_alloc "
         << " (5) __mt_alloc "
         << " (6) bitmap_allocator ";
    
    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;    
    
     
    //test all allocators' allocate() & deallocate();
    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);     //我刻意令參數為 2, 但這有何意義!! 一次要 2 個 ints? 
        
    __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);     //我刻意令參數為 3, 但這有何意義!! 一次要 3 個 ints? 
#endif          
}                                                           
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容