[GeekBand] STL與泛型編程-1

迭代器(iterator)
C++中的類模板(class template)與函數(shù)模板(funtion template)可以分別獨立完成數(shù)據(jù)容器(containers)和算法(algorithms)的設(shè)計飞涂,這樣就分別實現(xiàn)了容器與算法的泛型化较店,而這兩者之間的連接起來則依靠迭代器(iterators)實現(xiàn)容燕,因此一種算法可以通過迭代器的粘合而作用到不同的容器上梁呈。以下為應(yīng)用迭代器的簡單示例:

template <class InputIterator, class T>
InputIterator find(InputIterator first,
                           InputIterator last,
                           const T& value) {
    while (first != last && *first != value) {
        first++;
    }
    return first;
}

每種容器都有其對應(yīng)的迭代器官卡,下面定義的三種容器均有自身對應(yīng)的迭代器醋虏,上述find 算法通過迭代器而能適用于不同的容器。

std::vector<int> v(...)
std::list<int> l(...)
std::deque<int> d(...)
...
std::vector<int>::iterator itv = find(v.begin(), v.end(), value)
std::list<int>::iterator itl = find(l.begin(), l.end(), value)
std::deque<int>::iterator itd = find(d.begin(), d.end(), value)

迭代器是一種行為類似指針的對象颈嚼,迭代器這種類里面對 operator* 和 operator->進行了重載(overloading),因此可以像指針一樣進行內(nèi)容提領(lǐng)(deference)和成員訪問(member access)這兩項工作熔脂。

特性(traits)
算法中運用迭代器時,可能會用到其關(guān)聯(lián)型別(associated type)霞揉,包括以下五種:

  • value_type
  • difference_type
  • pointer
  • reference
  • iterator_category

其中 value_type 是迭代器所指對象的型別晰骑。假設(shè)算法中需要聲明一個以 value_type 為型別的變量,由于沒有C++不支持 typeof()硕舆,且 RTTI 中的 typeid()只能獲取型別名稱,不能用于變量聲明扬跋,所以需要采取特定的解決方法凌节。第一種可供考慮的解決方案就是利用函數(shù)模板的參數(shù)推導(argument deducation)機制 ,程序示例如下:

template <class I, class T>
void func_impl(I iter, T t) {
    T tmp;    // T 就是迭代器所指對象的型別倍奢,以此解決了上述問題
    ...    // 這里做原本 func( ) 應(yīng)該做的工作   
}

template <class I>
inline
void func(I iter) {
    func_impl(iter, *iter);
}

int main() {
    int i;
    func(&i);
}

如果需要以 value_type 作為函數(shù)返回值,則上述函數(shù)的參數(shù)推導機制將失效痪宰,此時可考慮聲明內(nèi)嵌型別來解決:

template <class T>
struct MyIter {
    typedef T value_type;    // 內(nèi)嵌型別聲明(nested type)
    T* ptr;
    MyIter(T* p = 0) : ptr(p) { }
    T& operator*() const { return *ptr; }
    ...
};

template <class I>
typename I::value_type    // 用 typename 聲明 func 的返回值型別
func(I ite) {
    return *ite;
}
...
MyIter<int> ite(new int(8));
cout << func(ite);    // 輸出:8

當?shù)鞑皇?class type畔裕,而是原生指針時,上述方法再次失效柴钻。此時可考慮用一個專門的 class template 來萃取迭代器的特性,并且以模板偏特化來應(yīng)對獲取原生指針的型別的問題:

template <class I>
struct iterator_traits {
    typedef typename I::value_type value_type;
};

應(yīng)對原生指針的特化版本如下:

template <class T>
struct iterator_traits<T*> {
    typedef T value_type;
};

運用模板類 iterator_traits 之后靠粪,函數(shù) func 可以寫成如下形式:

template <class I>
typename iterator_traits<I>::value_type
func(I ite) {
    return *ite;
}

Vector
Vector 是能夠存放任意型別的動態(tài)數(shù)組毫蚓,在內(nèi)存中是一段地址連續(xù)的空間,支持動態(tài)空間大小調(diào)整元潘,隨著元素的加入,vector 內(nèi)部會自動擴充內(nèi)存空間牲距。

  1. 創(chuàng)建 Vector
std::vector<T> v;
std::vector<T> v(n);    // 容量為 n
std::vector<T> v(n, i)    // 容量為 n,均初始化為 i
std::vector<T> copyOfV(v)
int array[] = {1,2,3,4,5,6,7,8,9,10}; std::vector<T> v(array, array + 10);
  1. 向 Vector 中添加元素
std::vector<std::wstring> v3;
for (std::size_t i = 0; i < 10; i++) {
std::wstringstream wss;
wss << TEXT("String[") << i << TEXT("]");
v3.push_back(wss.str());
}
  1. 判斷 Vector 是否為空
std::vector<std::wstring> v3;
bool isEmpty = v3.empty();
  1. 獲取 Vector 的大小
int array[] = {1,2,3,4,5,6,7,8,9,10};
std::vector<int> v(array, array + 10);
std::size vSize = v.size();
  1. 訪問 Vector 中元素
  • 調(diào)用 vector::at()牍鞠,進行邊界檢查
  • 調(diào)用 vector::operator[],不進行邊界檢查
  1. 從 Vector 中刪除元素
    • 清除整個 vector:clear
  • 彈出 vector 尾部元素:pop_back
  • 刪除 vector 中某一位置元素:erase
// 指定 iterator 處刪除某一元素
std::vector<int>::const_iterator it = v.begin();
v.erase(it + 1);  //刪除第二個元素
// 通過某一條件函數(shù)找到 vector 中需要刪除的元素
struct ContainString: public std::unary_function<std::wstring, bool> {
    ContainString(const std::wstring& wszMatch): m_wszMatch(wszMatch) { }
    bool operator() (const std::wstring& wszStringToMatch) const {
        return (wszMatchToMatch.find(m_wszString) != -1);
    }
    std::wstring m_wszString;
}
v.erase(std::remove_if(v.begin(), v.end(), ContainsString(L"C++")), v.end());

Deque
Deque 是一個能存放任意型別的雙向隊列萤晴,其提供的函數(shù)與 vector 類似胁后,采用了與 vector 不同的內(nèi)存管理方式:大塊分配內(nèi)存。Deque 新增了兩個函數(shù):

  • 在頭部插入元素:push_front
  • 在尾部彈出元素:pop_front
  1. 中間位置插入元素
    dqInt.insert(dqInt.begin() + 1, 9);  // 在第二個元素之前插入9
    
  2. 前向遍歷與反向遍歷
// 前向遍歷
deque<int>::iterator i, iend;
iend = dqInt.end();
for (i = dqInt.begin(); i != iend; ++i) {
    cout << *i << " ";
}
cout << endl;
// 反向遍歷
deque<int>::reverse_iterator ri, riend;
riend = dqInt.rend();
for(ri = dqInt.rbegin(); ri != riend; ++ri) {
    cout << *ri < " ";
}
cout << endl;

List
List 是一個能存放任意型別的雙向鏈表(doubly linked list)屯断。

  • 可以向鏈表中接入一個子鏈表(sub-list)
  • 優(yōu)點:
    1. 不使用連續(xù)內(nèi)存完成動態(tài)操作侣诺;
    2. 對于插入、刪除和替換等需要重排序列的操作剃氧,效率極高;
    3. 可在兩端隨意進行插入朋鞍、刪除操作妥箕;
  • 缺點:
    1. 不能進行內(nèi)部的隨機訪問,即不像 vector 那樣支持 operator [] 和vector.at()畦幢;
    2. 相對于verctor占用內(nèi)存多。
  1. 創(chuàng)建 list
std::list<int> l;
std::list<int> l(n);  // 容量為 n
std::list<int> l(n, x);  // 容量為 n瘦真,均初始化為 x
std::list<int> copyOfList(l);

std::wstring array[] = {TEXT("Str-1"), TEXT("Str-2"), TEXT("Str-3")};
std::list<std::wstring> l(array, array+3);
  1. 向 list 添加元素
std::list<std::wstring> l;
l.push_back(TEXT("Some text pushed at back"));
l.push_front(TEXT("Some text pushed at front"));
  1. 判斷 list 是否為空
std::list<std::wstring> l;
bool isEmpty = l.empty();
  1. 獲取 list 大小
std::wstring array[] = {TEXT("Str-1"), TEXT("Str-2"), TEXT("Str-3")};
std::list<std::wstring> l(array, array+3);
std::size listSize = l.size();
  1. 刪除 list 中元素
  • 清除整個 list:clear()黍瞧,內(nèi)部調(diào)用 erase(begin(), end())
  • 彈出 list 尾部元素:pop_back()
  • 彈出 list 頭部元素:pop_front()
  • 刪除 list 中指定元素:erase(), remove(),remove_if()
  1. 向 list 中插入元素
std::list<std::wstring>::const_iterator it = l.begin();
l.insert(it, anotherList.begin(), anotherList.end());
  1. 粘接 list:splice
// position為目標 list 位置印颤,x 為源 list,first 與 last 限定源的范圍
void splice ( iterator position, list<T, Allocator>& x ); 
void splice ( iterator position, list<T, Allocator>& x, iterator i );
void splice ( iterator position, list<T, Allocator>& x, 
                 iterator first, iterator last );
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末际看,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仲闽,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畏鼓,死亡現(xiàn)場離奇詭異,居然都是意外死亡云矫,警方通過查閱死者的電腦和手機汗菜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陨界,“玉大人,你說我怎么就攤上這事腮敌∏卫” “怎么了糜工?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵捌木,是天一觀的道長。 經(jīng)常有香客問我刨裆,道長彬檀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任凤覆,我火速辦了婚禮,結(jié)果婚禮上慈俯,老公的妹妹穿的比我還像新娘。我一直安慰自己贴膘,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布洋闽。 她就那樣靜靜地躺著,像睡著了一般诫舅。 火紅的嫁衣襯著肌膚如雪宫患。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天娃闲,我揣著相機與錄音,去河邊找鬼卷哩。 笑死,一個胖子當著我的面吹牛殉疼,可吹牛的內(nèi)容都是我干的捌年。 我是一名探鬼主播瓢娜,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼眠砾,長吁一口氣:“原來是場噩夢啊……” “哼托酸!你這毒婦竟也來了褒颈?” 一聲冷哼從身側(cè)響起励堡,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刨疼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揩慕,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谅河。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抵拘。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聘芜,靈堂內(nèi)的尸體忽然破棺而出不同,到底是詐尸還是另有隱情,我是刑警寧澤二拐,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布凳兵,位于F島的核電站,受9級特大地震影響庐扫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜形庭,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一萨醒、第九天 我趴在偏房一處隱蔽的房頂上張望斟珊。 院中可真熱鬧富纸,春花似錦、人聲如沸晓褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至埃元,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岛杀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工糊肠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人货裹。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓精偿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笔咽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

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