Boolan微專(zhuān)業(yè)-STL與泛型編程(Week02)

STL與泛型編程

主要內(nèi)容:

簡(jiǎn)單介紹了 OOP 和 GP 編程冀自。詳細(xì)剖析了 STL 中的分配器揉稚、list、Iterator熬粗、vector搀玖、array、forward_list

OOP(Object-Oriented Programming 面向?qū)ο缶幊蹋?vs. GP(Generic Programming 泛型編程)

OOP

  • OOP主要的思想是將datas和methods關(guān)聯(lián)在一起的思想驻呐。
  • 也就是數(shù)據(jù)放在類(lèi)中灌诅,操作數(shù)據(jù)的方法也是放在類(lèi)中芳来。(class 貓身上有毛,那么他必須有一個(gè)方法來(lái)管理他的毛猜拾,也就是舔毛()這個(gè)函數(shù)即舌。只需要貓咪.舔毛();來(lái)調(diào)用這個(gè)函數(shù),就可以管理和操作對(duì)應(yīng)的數(shù)據(jù))

GP

  • GP的主要思想是將datas和methods分開(kāi)挎袜。在STL中大量使用到了GP的思想顽聂,來(lái)實(shí)現(xiàn)了數(shù)據(jù)和算法的分離,那么盯仪,算法如何才能操作數(shù)據(jù)呢芜飘,這中間的橋梁就是Iterators(迭代器)了,通過(guò)Iterator磨总,算法可以從容器中獲取到需要的數(shù)據(jù),同樣也就可以起到操作數(shù)據(jù)的目的笼沥。
  • 為何STL會(huì)采用GP的思想呢蚪燕?其實(shí)使用了GP思想,類(lèi)和類(lèi)之間的關(guān)系不會(huì)那么緊密奔浅,也就不會(huì)產(chǎn)生很強(qiáng)的耦合性馆纳,便于不同的成員,協(xié)同開(kāi)發(fā)不同的模塊汹桦,有助于加快項(xiàng)目開(kāi)發(fā)得效率鲁驶,大家只需要依據(jù)“中間商”Iterator來(lái)編寫(xiě)各自代碼就行了。
  • 對(duì)于OOP來(lái)說(shuō)最好的一點(diǎn)就是舞骆,方法和數(shù)據(jù)在同一個(gè)類(lèi)中钥弯,那么方法是專(zhuān)門(mén)為類(lèi)所設(shè)計(jì)的。比較方便能夠管理其中的數(shù)據(jù)督禽。GP由于數(shù)據(jù)和方法分離脆霎,操作的時(shí)候,難免有些數(shù)據(jù)狈惫,不能被這個(gè)方法所操作睛蛛。比如,list 不能使用::sort() 進(jìn)行排序胧谈,那到底是為什么呢忆肾?
  • ::sort() 的源碼,發(fā)現(xiàn)問(wèn)題所在:
    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(RandomAccessterator first, RandomAccessIterator last, T*, Size depth_limit)
    {
        ......
        RandomAccessIterator cut = __unguarded_partition(first, last, T(__median(*first, *(first + (last - first)/2), *(last - 1))));
    //由于此處牽扯到了Iterator的下標(biāo)運(yùn)算
        //list不是一個(gè)連續(xù)空間菱肖,前后節(jié)點(diǎn)之間靠指針相連客冈,所以list 的Iterator不具備下表直接運(yùn)算的能力,所以蔑滓,list不能直接使用::sort()來(lái)進(jìn)行排序
    //也正是由于這個(gè)原因::sort() 只能為RandomAccessIterator來(lái)進(jìn)行排序
        ......
    }
    

分配器

分配器是容器管理內(nèi)存的工具郊酒,對(duì)于容器的效率起著比較重要的作用

  • 在正式開(kāi)始說(shuō)allocator之前遇绞,先說(shuō)幾句operator new()和 malloc()以及operator delete() 和free()
  • 在創(chuàng)建對(duì)象時(shí),會(huì)調(diào)用operator new()燎窘,而operator new()中分配內(nèi)存實(shí)際也還是調(diào)用有C語(yǔ)言的Runtime Library所提供的malloc()摹闽,再由系統(tǒng)來(lái)分配所需要的內(nèi)存;銷(xiāo)毀對(duì)象時(shí)褐健,則會(huì)使用operator delete()付鹿,而他實(shí)際會(huì)調(diào)用free()。
  • vc中的operator new()
    void *operator new (size_t size, const std::nothrow_t&)
    {
        void *p;
        while((p = malloc(size)) == 0)
        {
            _TRY_BEGIN
            if(_callnewh(size) == 0) break;
            _CATCH(std::bad_alloc) return(0);
            _CATCH_END
        }
        return (p);
    }
    

容器結(jié)構(gòu)分類(lèi)

序列式容器(Sequence Container)的衍生關(guān)系

  • array (C++2.0)連續(xù)空間
  • vector 連續(xù)空間
  • heap 以算法形式呈現(xiàn)(xxx_heap())
  • priority_queue
  • list 雙向鏈表
  • slist C++2.0中為forward_list,單向鏈表
  • deque 分段連續(xù)空間
  • stack Container Adapter
  • queue Container Adapter

關(guān)聯(lián)式容器(Associative Containers)的衍生關(guān)系(復(fù)合)

  • rb_tree 紅黑樹(shù)蚜迅,非公開(kāi)
  • set
  • map
  • multiset
  • multimap
  • hashtable非公開(kāi)
  • hash_set非標(biāo)準(zhǔn)舵匾,C++2.0為unordered_set
  • hash_map非標(biāo)準(zhǔn),C++2.0為unordered_map
  • hash_multiset非標(biāo)準(zhǔn)谁不,C++2.0為unordered_multiset
  • hash_mulitmap非標(biāo)準(zhǔn)坐梯,C++2.0為unordered_multimap

容器 list

template <class T>
struct __list_node{
    typedef void* void_pointer;
    void_pointer prev;
    void_pointer next;
    T data;
};

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;
};

template<class T, class Ref, class Ptr>
struct __list_iterator{
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
}
  • 內(nèi)存關(guān)系示意圖
    • list為一個(gè)循環(huán)鏈表(如圖),但是對(duì)于迭代器來(lái)說(shuō)刹帕,end()獲取到的并非容器中的最后一個(gè)元素吵血,而應(yīng)該是,最后一個(gè)元素之后的空元素偷溺,所以在list實(shí)現(xiàn)的時(shí)蹋辅,可以看到,end()指向了一個(gè)灰色的區(qū)域挫掏,這個(gè)區(qū)域?qū)嶋H就是end()指向的非容器內(nèi)元素的區(qū)域
    • 由于list非連續(xù)空間侦另,所以Iterator在++時(shí),如果不作調(diào)整尉共,不會(huì)默認(rèn)的移動(dòng)到下一個(gè)不連續(xù)空間褒傅,所以,為了讓Iterator能夠和指針的用法相似爸邢,Iterator一定是一個(gè)class
    •   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 nod;
        
            reference operator*() const{
                return (*node).data;
            }
            pointer operator->() const {
                return &(operator*());
            }
            self& operator++(){//前++
                node = (link_type)((*node).next); return *this;
            }
            self operator++(int){//后++樊卓,參數(shù)實(shí)際無(wú)意義
                self temp = *this; ++*this; return tmp;
            }
        };
      
      

Iterator 的設(shè)計(jì)原則

算法要求這幾項(xiàng)的類(lèi)型必須指定出來(lái)

  • 算法(algorithms)在操作容器(Container)中的數(shù)據(jù)需要通過(guò)Iterator知道的信息如下:
    • iterator_category:Iterator的性質(zhì),例如是否可以雙向查詢(xún)
    • ifference_type:兩個(gè)Iterator之間的距離的type(int杠河、unsigned int)碌尔,決定了容器可以容納多少元素
    • value_type:元素本身的type
    • reference:引用
    • pointer:指針
    • 在Iterator的設(shè)計(jì)時(shí),必須有這五種associated types
  • traits的引入
    • 如果Iterator不是一個(gè)class的情況券敌,如果這樣的情況唾戚,無(wú)法從一個(gè)指針中獲取以上的幾種類(lèi)型,那么這時(shí)候待诅,需要一個(gè)“中介”來(lái)去協(xié)調(diào)這件事叹坦,這時(shí)候就出現(xiàn)了一個(gè)traits的機(jī)制
    • 這個(gè)traits可以區(qū)分到底是class設(shè)計(jì)的Iterator,也能夠區(qū)分是指針傳入的Iterator
    // traits的設(shè)計(jì)
    template<class I>
    struct iterator_traits{
        typedef typename I::value_type value_type;
        typedef typename I::iterator_category
        typedef typename I::difference_type
        typedef typename I::pointer
        typedef typename I::reference
    };
    
    //針對(duì)指針的兩種偏特化
    template<class T>
    struct iterator_traits<T*>{
        typedef T value_type;
        typedef random_access_iterator_tag iterator_category;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;
    };
    
    template <class T>
    struct iterator_traits<const T*>{
        typedef T value_type;
        typedef random_access_iterator_tag iterator_category;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;
    }
    
    // traits的使用
    template<typename I, ....>
    void algorithm(......){
        typename iterator_traits<I>::value_type v1;
    } 
    
  • 根據(jù)偏特化卑雁,如果傳入的為指針就會(huì)自動(dòng)進(jìn)入偏特化的部分募书,那么就根據(jù)偏特化來(lái)獲取響應(yīng)信息
  • 各式各樣的traits以及對(duì)應(yīng)的頭文件
    • 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++/bits/array.h

容器Vector

  • vector根據(jù)三個(gè)指針就可以控制全部?jī)?nèi)容 iterator start;绪囱、 iterator finish;、iterator end_of_storage;
    其中finish指向最后一個(gè)元素之后的位置莹捡。
    template <class T, class Alloc = alloc>
    class vector
    {
    public:
        typedef  T value_type;
        typedef value_type* iterator;
        typedef value_tyle&  reference;
        typedef size_t  size_type;
    protected:
        iterator start;
        iterator finish;
        iterator end_of_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); }
    }
    
  • 二倍成長(zhǎng)
    • 對(duì)于內(nèi)存來(lái)說(shuō)沒(méi)辦法實(shí)現(xiàn)原地?cái)U(kuò)充鬼吵,因?yàn)榍昂蠖伎赡艽嬖谥渌绦虻臄?shù)據(jù),如果擴(kuò)充篮赢,意味著會(huì)要影響到其他程序齿椅,并且操作系統(tǒng)也不允許這樣干。那么對(duì)于vector來(lái)說(shuō)启泣,hi如何來(lái)實(shí)現(xiàn)擴(kuò)充的呢涣脚?那么再擴(kuò)充的時(shí)候,需要在內(nèi)存的其他區(qū)域找到空間寥茫,在新找到的空間進(jìn)行擴(kuò)充完成后遣蚀,再將數(shù)據(jù)復(fù)制到新開(kāi)辟的空間中。而且每次增長(zhǎng)的空間都是以?xún)杀蹲鳛榛鶞?zhǔn)纱耻。
  • 存入元素和兩杯增長(zhǎng)的代碼
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){//空間夠用
        //在備用空間起始處建一個(gè)元素妙同,并以vector最后一個(gè)元素為其初值
        construct(finish, *(finish - 1);
        ++finish;
        T x_copy = x;
        copy_backward(postion, finish - 2, finish - 1);
        *postion = 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);
        //以上分配原則:剮原大小為0,分配1膝迎;不為0,分配原大小的兩倍胰耗;前半段用來(lái)放置原數(shù)據(jù)限次,后半段用來(lái)放置新數(shù)據(jù)
        iterator new_finish = new start;
        try{
            //將原vector的內(nèi)容拷貝到新的vector
            new_finish = uninitialized_copy(start, position, new_start);
            construnct(new_finish, x);//為新元素設(shè)置初值x
            ++new_finish;
            //拷貝安插點(diǎn)后的原內(nèi)容
            new_finish = uninitialized_copy(postion, finish, new_finish);
        }
        catch(...){
              destory(new_start, new_finish);
            data_allocator::deallocate(new_start, len);
          throwl
        }
        //析構(gòu)并釋放元vector
        destory(begin(), end());
        //調(diào)整迭代器,指向新的vector
        deallocate();
        start = new_start;
        finish = new_finish;
        end_of_storage = new_start + len;
    }
}

容器array

    template<typename _Tp, std::size_t _Nm>
    struct array{
    typedef _Tp;
    typedef _Tp*;
    typedef value_type*;
    
    value_type _M_instance[_Nm? _Nm: 1];
    iterator begin(){
        return iterator(&_M_instance[0]);
    }
    iterator end(){
        return iterator(&_M_instance[_Nm]);
    }
  }

forward_list

  • 單向鏈表柴灯,具體可以參考list(雙向鏈表)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卖漫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赠群,更是在濱河造成了極大的恐慌羊始,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查描,死亡現(xiàn)場(chǎng)離奇詭異突委,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)冬三,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)匀油,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人勾笆,你說(shuō)我怎么就攤上這事敌蚜。” “怎么了窝爪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵弛车,是天一觀(guān)的道長(zhǎng)齐媒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)纷跛,這世上最難降的妖魔是什么喻括? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮忽舟,結(jié)果婚禮上双妨,老公的妹妹穿的比我還像新娘。我一直安慰自己叮阅,他們只是感情好刁品,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著浩姥,像睡著了一般挑随。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勒叠,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天兜挨,我揣著相機(jī)與錄音,去河邊找鬼眯分。 笑死拌汇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弊决。 我是一名探鬼主播噪舀,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼飘诗!你這毒婦竟也來(lái)了与倡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昆稿,失蹤者是張志新(化名)和其女友劉穎纺座,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體溉潭,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡净响,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喳瓣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片别惦。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夫椭,靈堂內(nèi)的尸體忽然破棺而出掸掸,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響斩跌,放射性物質(zhì)發(fā)生泄漏懒叛。R本人自食惡果不足惜叁征,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦荒给、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蛔趴,卻和暖如春挑辆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孝情。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工鱼蝉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箫荡。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓魁亦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親羔挡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吉挣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容