STL 原始碼剖析 deque實現原始碼
#ifndef _HJSTL_DEQUE_H_ #define _HJSTL_DEQUE_H_ /* * Author:hujian * Time:2016/4/28 * discription:this file is about deque structure. * */ #include "hjstl_alloc.h" #include "hjstl_construct.h" #include "hjstl_iterator.h" #include "hjstl_uninitialized.h" #define _HJSTL_DEQUE_PUBLIC_ public #define _HJSTL_DEQUE_PRIVATE_ private #define _HJSTL_DEQUE_PROTECTED_ protected //deque buffer size inline size_t __HJSTL_deque_buf_size(size_t n, size_t sz){ return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1)); } //the deque iterator.this is very complex. template<class Type,class Ref,class Ptr,size_t BufSize/*you can change the size*/> struct __HJSTL_deque_iterator{ typedef __HJSTL_deque_iterator<Type, Ref&, Ptr*, BufSize> iterator; typedef __HJSTL_deque_iterator<Type, const Ref&, const Ptr*, BufSize> const_iterator; static size_t buffer_size(){ //you want to set the buffer size return __HJSTL_deque_buf_size(BufSize, sizeof(Type)); } typedef hjstl_random_access_iterator_tag hjstl_iterator_category; typedef Type hjstl_value_type; typedef Ptr hjstl_pointer; typedef Ref hjstl_reference; typedef size_t size_type; typedef ptrdiff_t hjstl_difference_type; typedef Type** map_pointer; typedef __HJSTL_deque_iterator self; Type* cur; //the iterator's buffer's current element. Type* first;//the iterator's buffer's head element Type* last;//the iterator's buffer's tail element map_pointer node;//this node pointer to the controller. //constructor __HJSTL_deque_iterator(Type* x,map_pointer y) :cur(x), first(*y), last(*y + buffer_size(), node(y)){} __HJSTL_deque_iterator() :cur(0), first(0), last(0), node(0){} __HJSTL_deque_iterator(const iterator& x) :cur(x.cur), first(x.first), last(x.last), node(x.node){} hjstl_reference operator*() const { return *cur; } hjstl_pointer operator->() const { return &(operator*()); } hjstl_difference_type operator -(const self&x) const { return hjstl_difference_type(buffer_size())*(node - x.node - 1) + (cur - first) + (x.last - x.cur); } self& operator ++(){ //++iterator ++cur; if (cur == last){ set_node(node + 1); cur = first; } return *this; } self operator++(int) {//iterator++ self tmp = *this; ++*this; return tmp; } self& operator --(){//--iterator if (cur == first){ set_node(node - 1); cur = last; } --cur; return *this; } self operator --(int){//iterator-- self tmp = *this; --*this; return tmp; } self& operator +=(hjstl_difference_type n){//iterator += n hjstl_difference_type offset = n + (cur - first); //ok,aim index is at the same buffer,just pointer to.. if (offset >= 0 && offset < hjstl_difference_type(buffer_size)){ cur += n; } else{//difference buffer.so,we need to do more thing hjstl_difference_type node_offset = offset>0/*forward*/ ? offset / hjstl_difference_type(buffer_size) : -hjstl_difference_type(-offset - 1) - 1; //goto the node. set_node(node + node_offset); //goto the cur we should. cur = first + (offset - node_offset*hjstl_difference_type(buffer_size())); } return *this; } //ok,we have implemented the +=,then the + is so easy to implement self operator +(hjstl_difference_type n) const { self tmp = *this; return tmp += n; } //yeah,do you know we can use add to implement minus..? self & operator -=(hjstl_difference_type n){ return *this += -n; } //:> self operator -(hjstl_difference_type n) const { self tmp = *this; return tmp -= n; } //random put/get hjstl_reference operator[](hjstl_difference_type n) const { return *(*this + n); } bool operator ==(const self& x) const { return cur == x.cur; } bool operator !=(const self& x) const { return cur != x.cur; } bool operator<(const self&x)const { return (node == x.node) ? (cur < x.cur) : (node < x.node); } //set node.goto.. void set_node(map_pointer new_node) { node = new_node; first = *new_node; last = first + hjstl_difference_type(buffer_size()); } }; template<class Type,class Ref,class Ptr,size_t BufSz> inline hjstl_random_access_iterator_tag hjstl_iterator_category(const __HJSTL_deque_iterator<Type, Ref, Ptr, BufSz>&){ return hjstl_random_access_iterator_tag(); } template<class Type,class Ref,class Ptr,size_t BufSz> inline Type* hjstl_value_type(const __HJSTL_deque_iterator<Type, Ref, Ptr,BufSz>&){ return 0; } template<class Type, class Ref, class Ptr,size_t BufSz> inline ptrdiff_t* hjstl_distance_type(const __HJSTL_deque_iterator<Type, Ref, Ptr, BufSz>&){ return 0; } //the follow codes is about the deque. //you can set the block's size,the default block size is 512 bytes template<class Type,class Alloc=HJSTL_Alloc::HJSTL_Allocate_default,size_t BufSize=0> class _HJSTL_deque{ _HJSTL_DEQUE_PUBLIC_: typedef Type value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; //the deque's iterator. typedef __HJSTL_deque_iterator<Type, Type&, Type*, BufSize> iterator; typedef __HJSTL_deque_iterator<Type, const Type&, const Type*, BufSize> const_iterator; _HJSTL_DEQUE_PROTECTED_: //pointer of pointer of Type. typedef pointer* map_pointer; //the data allocator. typedef _HJSTL_simple_alloc<value_type, Alloc> data_allocator; //map node allocator typedef _HJSTL_simple_alloc<pointer, Alloc> map_allocator; //get the buffer size static size_type buffer_size(){ return __HJSTL_deque_buf_size(BufSize, sizeof(value_type)); } //the initialze map size(the nodes of the map in the beginning) static size_type initial_map_size(){ return 8;//you can change here to adjust your map nodes. } //the data member. iterator start;//the first node of map. iterator finish;//the last node of map //the map.this is an array.stored the node pointer. //and the node is pointer too. map_pointer map; //the map size size_type map_size; _HJSTL_DEQUE_PUBLIC_://get member. iterator begin(){ return start; } iterator end(){ return finish; } const iterator begin() const { return start; } const iterator end() const { return finish; } reference operator[](size_type n){ return start[difference_type(n)]; } const reference operator[](size_type n) const{ return start[difference_type(n)]; } reference front(){ return *start;//the first node's first element. } reference back(){ iterator tmp = finish; //the finish is empry. --tmp; return *tmp; } const reference front() const{ return *start;//the first node's first element. } const reference back() const{ const_iterator tmp = finish; //the finish is empry. --tmp; return *tmp; } //the size of this eque //NOTICE:the operator '-' is not so simple.you need to know that. size_type size()const{ return finish - start; } //-1 is max number... size_type max_size()const { return size_type(-1); } //is empty? bool empty(){ return start == finish; } _HJSTL_DEQUE_PUBLIC_://the follow is constructor _HJSTL_deque() : start(), finish(), map(0){ //just set up an default deque for user. create_map_and_nodes(0); } _HJSTL_deque(const _HJSTL_deque&x) :start(), finish, map(0), map_size(0) { create_map_and_nodes(x.size()); try{ uninitialized_copy(x.begin(), x.end(), start); } catch (...){ //error destroy_map_and_nodes(); } } _HJSTL_deque(size_type n, const value_type& value) :start(), finish(), map(0), map_size(0) { fill_initialze(n, value); } _HJSTL_deque(int n, const value_type& value) :start(), finish(), map(0), map_size(0) { fill_initialze(n, value); } _HJSTL_deque(long n, const value_type& value) :start(), finish(), map(0), map_size(0) { fill_initialze(n, value); } explicit _HJSTL_deque(size_type n) :start(), finish(), map(0), map_size(0) { fill_initialze(n, value_type()); } template<class InputIterator> _HJSTL_deque(InputIterator first, InputIterator last) : start(), finish(), map(0), map_size(0) { range_initialze(first, last, hjstl_iterator_category(first)); } _HJSTL_deque(const value_type* first, const value_type* last) :start(), finish(), map(0), map_size(0) { create_map_and_nodes(last-first); try{ uninitialized_copy(first, last, start); } catch (...){ destroy_map_and_nodes(); } } _HJSTL_deque(const_iterator first, const_iterator last) :start(), finish(), map(0), map_size(0) { create_map_and_nodes(last - first); try{ uninitialized_copy(first, last, start); } catch (...){ destroy_map_and_nodes(); } } //deconstructor ~_HJSTL_deque(){ destroy(start, finish); destroy_map_and_nodes(); } //function. _HJSTL_deque& operator =(const _HJSTL_deque& x) { const size_type len = size(); if (&x != this){//difference deque earse(copy(x.begin(), x.end(), start), finish); } else{ const_iterator mid = x.begin() + difference_type(len); copy(x.begin(), mid, start); insert(finish, mid, x.end()); } return *this; } //erase an iterator iterator erase(iterator pos) { iterator next = pos; ++next; difference_type index = pos - start; //the length of before remove element. if (index < (size() >> 1/*just like size()/2*/)){//less copy_backward(start, pos, next); pop_front();//delete the pos's value } else{//more. copy(next, finish, pos); pop_back();//delete the pos'value } //return the pos's value return start + index; } //erase the range [first,last) iterator erase(iterator first, iterator last) { //if you want to clear the deque.just use clear if (first == start&&last == finish){ clear(); return finish; } else{ difference_type len = last - first; difference_type elements_before = first - start; if (elements_before < (size() - len) / 2)//the before elements less { copy_backward(start, first, last); //the new start iterator new_start = start + len; //destructor the elemenst we do not want to left destroy(start, new_start); //back the memory to the memeory pool for (map_pointer cur = start.node; cur < new_start.node; ++cur){ data_allocator::deallocate(*cur, buffer_size()); } //set the start start = new_start; } else{//the length of range [first,last) ->before>after copy(last, finish, first); iterator new_finish = finish - len; destroy(new_finish, finish); for (map_pointer cur = new_finish.node + 1; cur <= finish.node; ++cur){ data_allocator::deallocate(*cur, buffer_size()); } //set the new finish finish = new_finish; } return start + elements_before; } } //insert an item into the deque. //this is the insert aux iterator insert_aux(iterator pos, const value_type& value) { difference_type index = pos - start; value_type copy_v = value; if (index < size() / 2){//before<after //insert into the front values(front()) push_back(front()); //move the elements. iterator front_1 = start; ++front_1; iterator front_2 = front_1; ++front_2; //re get-the pos's iterator pos = start + index; iterator pos_1 = pos; ++pos_1; //copy data. copy(front_2, pos, front_1); } else{//before>=after push_back(back()); iterator back_1 = finish; --back_1; iterator back_2 = back_1; --back_2; pos = start + index; copy(pos, back_2, back_1); } //assignment. *pos = copy_v; return pos; } //this is the insert iterator insert(iterator position, const value_type& value) { //front or back? if (position.cur == start.cur){ push_front(value); return start; } else if (position.cur == finish.cur){ push_back(value); iterator tmp = finish; --tmp; return tmp; } else{ return insert_aux(position, value); } } //insert iterator insert(iterator position){ //empty initialze return insert(position, value_type()); } //realloc the map void reallocate_map(size_type nodes_to_add, bool add_at_front/*opt*/) { size_type old_num_nodes = finish - start + 1; size_type new_num_nodes = old_num_nodes + nodes_to_add; map_pointer new_nstart; if (map_size > 2 * new_num_nodes){ new_nstart = map + (map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0); if (new_nstart < start.node){ copy(start.node, finish.node + 1, new_nstart); } else{ copy_backward(start.node, finish.node + 1,new_nstart+ old_num_nodes); } } else{ size_type new_map_size = map_size + (map_size > nodes_to_add ? map_size : nodes_to_add) + 1; map_pointer new_map = map_allocator::allocate(new_map_size); new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0); copy(start.node, finish.node + 1, new_nstart); map_allocator::deallocate(map, map_size); //set the new map.attr map = new_map; map_size = new_map_size; } start.set_node(new_nstart); finish.set_node(new_nstart + old_num_nodes + 1); } //reserve map at back //default add 1 node void reserver_map_at_back(size_type nodes_to_add = 1) { if (nodes_to_add + 1 > map_size - (finish.node - map)){ reallocate_map(nodes_to_add, false); } } void reserver_map_at_front(size_type nodes_to_add = 1) { if (nodes_to_add > start.node - map){ reallocate_map(nodes_to_add, true); } } //just swap void swap(_HJSTL_deque& x) { std::swap(start, x.start); std::swap(finish, x.finish); std::swap(map, x.map); std::swap(map_size, x.map_size); } //push_back void push_back(const value_type& value) { if (finish.cur != finish.last - 1){ construct(finish.cur, value); ++finish.cur; } else{//i let the another function do this push_back_aux(value); } } //push_back_aux void push_back_aux(const value_type& value) { value_type copy_v = value; reserver_map_at_back(); //alloc an new node *(finish.node + 1) = allocate_node(); try{ construct(finish.cur, copy_v); finish.set_node(finish.node + 1); finish.cur = finish.first; } catch (...){ //if error,just deallocate the alloc-ed memory. deallocate_node(*(finish.node + 1)); } } //push_front_aux void push_front_aux(const value_type& value) { value_type copy_v = value; reserver_map_at_front(); //allocate an new node *(start.node-1)=allocate_node(); try{ start.set_node(start.node - 1); start.cur = start.last - 1; construct(start.cur, copy_v); } catch (...){ //error start.set_node(start.node + 1); start.cur = start.first; deallocate_node(*(start.node - 1)); } } //push_front void push_front(const value_type& value) { if (start.cur != start.first){ construct(start.cur, value); --start.cur; } else{ push_front_aux(value); } } //pop_front_aux //edge... void pop_front_aux() { destroy(start.cur); deallocate_node(start.first); start.set_node(start.node + 1); start.cur = start.first; } //pop_back_aux //edge void pop_back_aux() { deallocate_node(finish.first); finish.set_node(finish.node - 1); finish.cur = finish.last - 1; destroy(finish.cur); } //pop_back void pop_back() { if (finish.cur != finish.first){ --finish.cur; destroy(finish.cur); } else{ pop_back_aux(); } } //pop_front void pop_front() { if (start.cur != start.last - 1){ destroy(start.cur); ++start.cur; } else { pop_front_aux(); } } _HJSTL_DEQUE_PROTECTED_://some useful function //allocate an node pointer allocate_node(){ return data_allocator::allocate(buffer_size()); } //deallocate an node void deallocate_node(pointer ptr){ data_allocator::deallocate(ptr, buffer_size()); } //set up a deque with num_elements. void create_map_and_nodes(size_type num_elements) { //the needed nodes size_type num_nodes = num_elements / buffer_size() + 1; //get the map size map_size = initial_map_size()> (num_nodes+2) ? initial_map_size() : num_nodes+2; //alloc map_size's nodes for map. map = map_allocator::allocate(map_size); //in the mid. map_pointer nstart, nfinish; nstart = map + (map_size - num_nodes) / 2; nfinish = nstart + num_nodes - 1; map_pointer cur; try{ //alloc for each node for (cur = nstart; cur<=nfinish; cur++){ *cur = allocate_node(); } } catch (...){ //deallocate. for (map_pointer n = nstart; n < cur; n++){ deallocate_node(*n); } map_allocator::deallocate(map, map_size); } //set the start and finish start.set_node(nstart); finish.set_node(nfinish); start.cur = start.first; //make sure you can understand the follow code. finish.cur = finish.first + num_elements%buffer_size(); } //destroy map and nodes void destroy_map_and_nodes(){ for (map_pointer cur = start.node; cur <= finish.node; ++cur){ deallocate_node(*cur); } map_allocator::deallocate(map, map_size); } //fill initialze void fill_initialze(size_type n, const value_type& value) { create_map_and_nodes(n); map_pointer cur; try{ for (cur = start.node; cur < finish.node; ++cur){ uninitialized_fill(*cur, *cur + buffer_size(), value); } //finish node initialze uninitialized_fill(finish.first, finish.cur, value); } catch (...){ //if not succeed,destory the old.. for (map_pointer n = start.node; n < cur; ++n){ destroy(*n, *n + buffer_size()); } destroy_map_and_nodes(); } } //range initialze template<class InputIterator> void range_initialze(InputIterator first, InputIterator last, hjstl_input_iterator_tag) { create_map_and_nodes(0); while (first != last){ push_back(*first++); } } template<class ForwardIterator> void range_initialze(ForwardIterator first, ForwardIterator last, hjstl_forward_iterator_tag) { size_type n = 0; hjstl_distance(first, last, n); create_map_and_nodes(n); try{ uninitialized_copy(first, last, start); } catch (...){ destroy_map_and_nodes(); } } _HJSTL_DEQUE_PUBLIC_: //clear this deque //we need to left one buffer for this empty deque. // void clear() { for (map_pointer node = start.node + 1; node < finish.node; ++node){ destroy(*node, *node + buffer_size()); data_allocator::deallocate(*node, buffer_size()); } //if we have at least 2 buffer left,just left the head buffer if (start.node != finish.node){ destroy(start.cur, start.last); destroy(finish.first, finish.cur); data_allocator::deallocate(finish.first, buffer_size()); } //else,just one buffer left now. //NOTICE:do not back the memory to memory pool. //this is the must-left buffer in an empty deue. else{ destroy(start.cur, finish.cur); } //set the finish finish = start;//means this is an empty deque,you can look up the //function empty() to check the algorithm } };//end of hjstl deque ///<2016/4/28 hujian deque> #endif //end of _HJSTL_DEQUE_H_
拖了很久,前面寫vector和list的時候因為有些地方需要重新改動,比如要去修改(增加特性支援)迭代器部分或者記憶體管理部分。寫完vector之後應該說整個流程都打通了,接下來就是填程式碼了。
在寫list的時候,主要是為了強化對連結串列這種資料結構的認識。確實,如果能把list裡面的連結串列操作搞明白了,我覺得對於連結串列可以說是掌握了。
特別是,list實現時採用的是迴圈雙鏈表,所以只要你明白了他的執行原理及結構,那麼什麼單向連結串列,雙向連結串列,迴圈連結串列都不在話下。
那如果說重寫list最大的收穫是加深了對連結串列的理解,重寫deque帶來了什麼呢?
看了原始碼之後,你會發現deque是所有容器中程式碼量最多的。這也從一個側面反映出了deque的複雜性。
但是,deque不是採用連結串列,而是線性表。和vector很像,只是vector只能單方向操作,而deque支援頭尾操作,而且效率很高。
deque的複雜性在於他的迭代器設計和記憶體管理,特別是迭代器設計,是整個deque設計過程中的重點和難點。因為deque是一段一段的空間組成的
“連續”空間,所以,對於介面來說,需要實現像vector一樣的自然操作,那vector用的是線性表,沒什麼複雜的,但是deque不是線性表,deque一方面解決了
vector記憶體生長時的複雜度之外,還加深了存取操作,但隨之而來的是加大了設計迭代器的複雜性。
關於deque如何設計迭代器與如何管理記憶體,可以在我自己整理的檔案中看到,關於整個檔案,我將把從開始到現在實現的所有檔案和說明文件都發到
github,下一步有興趣的同學可以下載來看看......
因為大家可能在windows下看的,直接編譯SGI的STL需要花很大的功夫,還不一定能成功,我寫的你不僅可以在windows下編譯,還可以在linux下編譯,不僅
平臺無關,還編譯器無關~~~(對於需要做少量修改的地方,大家自行處理)
ok,下面是原始碼,我會在下一篇文章中貼出github地址,大家可以下載。
相關推薦
STL 原始碼剖析 deque實現原始碼
#ifndef _HJSTL_DEQUE_H_ #define _HJSTL_DEQUE_H_ /* * Author:hujian * Time:2016/4/28 * discription:this file is about deque structur
STL原始碼剖析——deque的實現原理和使用方法詳解
Deque 簡介 deque是“double—ended queue”的縮寫,和vector一樣都是STL的容器,deque 是雙端陣列,而 vector 是單端的。 deque 在介面上和 vector 非常相似,在許多操作的地方
【Java集合原始碼剖析】ArrayList原始碼剖析
本篇博文參加了CSDN博文大賽,如果您覺得這篇博文不錯,希望您能幫我投一票,謝謝!ArrayList簡介 ArrayList是基於陣列實現的,是一個動態陣列,其容量能自動增長,類似於C語言中的動態申請記憶體,動態增長記憶體。 ArrayList不是執行緒安全的,只
【Java集合原始碼剖析】TreeMap原始碼剖析
前言 本文不打算延續前幾篇的風格(對所有的原始碼加入註釋),因為要理解透TreeMap的所有原始碼,對博主來說,確實需要耗費大量的時間和經歷,目前看來不大可能有這麼多時間的投入,故這裡意在通過於閱讀原始碼對TreeMap有個巨集觀上的把握,並就其中一些方法的實現做比較深
使用C++STL中的deque實現作業系統FIFO、LRU頁面置換演算法
#include <iostream> #include <deque>//雙端佇列所在的標頭檔案 #include <algorithm>//find()函式所在的標頭檔案 using namespace std; cons
a集合原始碼剖析:TreeMap原始碼剖析
▷▷▷前言 本文不打算延續前幾篇的風格(對所有的原始碼加入註釋),因為要理解透TreeMap的所有原始碼,對博主來說,確實需要
rocketmq之原始碼分析netty實現原始碼(六)
netty的服務端核心屬性 public class NettyRemotingServer extends NettyRemo
STL原始碼剖析——stack的實現原理和使用方法詳解
Stack 簡介 stack 是堆疊容器,是一種“先進後出”的容器。 stack 是簡單地裝飾 deque 容器而成為另外一種容器。 使用 stack 時需要加上標頭檔案 #include<s
STL原始碼剖析(四)序列式容器--deque
文章目錄 1. 關於deque 1.1 deque概述 1.2 deque與vector區別 2. deque構成 3. deque的迭代器 4. deque構造與記憶體管理 4.1 deque構造
STL原始碼剖析之stl_deque的實現(二)
STL中deque(雙端佇列)是一種非常重要的結構,stack,與queue底層都是藉助deque. deque(雙端佇列)是一種雙向開口的連續性空間,雙向開口意思是可以在頭尾兩端做元素的插入和刪除操作。deque和vector最大的差異在於deque允許常數時間內對起頭端
STL deque原始碼剖析
deque(double-ended queue)是一種雙向開口的序列容器,可以在頭部和尾部進行push或pop操作,與vector不同,deque不是真正的連續線性空間,它是由分段連續空間動態組合而成。 map是一個二重指標,指向一個指標陣列,陣列中
【原始碼剖析】threadpool —— 基於 pthread 實現的簡單執行緒池
部落格新地址:https://github.com/AngryHacker/articles/issues/1#issue-369867252 執行緒池介紹 執行緒池可以說是專案中經常會用到的元件,在這裡假設讀者都有一定的多執行緒基礎,如果沒有的話不妨在這裡進行了解:POSIX
【原始碼剖析】MemoryPool —— 簡單高效的記憶體池 allocator 實現
什麼是記憶體池?什麼是 C++ 的 allocator? 記憶體池簡單說,是為了減少頻繁使用 malloc/free new/delete 等系統呼叫而造成的效能損耗而設計的。當我們的程式需要頻繁地申請和釋放
【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(三)
新地址:https://github.com/AngryHacker/articles/issues/5#issue-372211594 童鞋,我就知道你是個好學滴好孩子~來吧,讓我們進行最後的探(zuo)索(si)!
【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(二)
客官您終於回頭了!讓我們本著探(zuo)索(si)精神把 session.py 看完吧... 首先看看需要的庫: pickle 一個用於序列化反序列化的庫(聽
STL原始碼剖析——序列式容器
序列式容器 所謂序列化容器,其中的元素都可序,但未必有序。C++語言本省提供了一個序列式容器array,STL另外提供了vector,list,deque,stack,queue,priority_queue等序列式容器。其中stack和queue由於只是將deque作為底層
STL原始碼剖析——list容器的排序演算法sort()
原文:https://blog.csdn.net/chenhanzhun/article/details/39337331 前言 由於STL本身的排序演算法sort接受的輸入迭代器是隨機訪問迭代器,但是雙向list連結串列容器的訪問方式是雙向迭代器,因此,不能使用
stl vector原始碼剖析
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
STL原始碼剖析(三)迭代器與traits程式設計
文章目錄 1. 迭代器概念 1.1 基本概念 1.2 迭代器設計理念 2. 引出traits程式設計 3. traits程式設計 3.1 traits程式設計技術 3.2 partial special
STL原始碼剖析(二)空間配置器
歡迎大家來訪二笙的小房子,一同學習分享生活! 文章目錄 1. 寫在前面 2. SGI空間配置器 2.1 SGI標準空間配置器 2.2 SGI特殊的空間配置器,std::alloc 2.3 構造和析構基本工具 2.4 空間