《Effective STL》 讀書筆記

Effective STL

剝離

向基類對象的容器中插入派生類對象,派生類對象獨有的特性會丟失

empty

檢查容器是否爲空用empty而不是size

善於使用區間成員函數(assign,etc)

v1.assign(v2.begin() + v2.size()/2, v2.end())

16.將vector和string傳給舊的API(c api)

vector元素是連續存儲在內存中的

if (!v.empty()) {
  func(&v[0]);
}

不能用v.begin(),因爲這將返回一個迭代器,而不是指針

string元素不一定是連續存儲在內存中的,所以有專門的成員函數

s.c_str()

17.使用swap將多餘內存還給系統

`vector<int> contestents(10, 0);
  contestents.pop_back();
  cout << "Capacity is " << contestents.capacity() << "\n";// 10
  vector<int>(contestents).swap(contestents);
  cout << "Capacity is " << contestents.capacity() << "\n";// 9`

C++11起有了成員函數shrink_to_fit()

18.vector

失敗的實驗,可以採用deque

19.相等與等價

等價

!(a < b) && !(a > b)

20.爲包含指針內容的關聯容器指定比較類型

set裏面存string*,但是想要set按照字符串的字典序排序。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <set>

using namespace std;

struct StringPtrLess:
    public binary_function<const string*, const string*, bool> {//binary_function 於 C++11 棄用並於 C++17 移除。
        bool operator() (const string *ps1, const string *ps2) const {
            return *ps1 < *ps2;
        }
    };

int main()
{
    set<string*, StringPtrLess> ss;
    string a = "sadad";
    string b = "dsfaf";
    ss.insert(&a);
    ss.insert(&b);
    for (auto it : ss) {
        cout << *it << "\n";
    }
}

模板類型:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <set>

using namespace std;

struct DereferenceLess {
    template<typename PtrType>
    bool operator() (PtrType pT1, PtrType pT2) const {
        return *pT1 < *pT2;
    }
};
int main()
{
    set<string*, DereferenceLess> ss;
    string a = "sadad";
    string b = "dsfaf";
    ss.insert(&a);
    ss.insert(&b);
    for (auto it : ss) {
        cout << *it << "\n";
    }
}

21.總是讓比較函數在等值情況下返回false

如果set中的比較函數是operator<=,那麼等價性的判斷就 !(a <= b) && !(a >= b),顯然爲false,那麼就認爲 a 和 b 是不等價的。

那麼set中就會包含兩個相等的值,就破壞了 set 容器。

用於對關聯容器排序的比較函數必須爲他們所比較對象定義一個”嚴格的弱序化“

22.切勿直接修改 set 或 multiset中的鍵

map 和 multimap 中的鍵是 const 的

set 和 multiset中的鍵是非 const 的

試圖修改 set 或 multiset 元素的代碼將是不可移植的

應對方案:

  • 不考慮移植性,非鍵部分可以改動
  • 考慮移植性,修改非鍵部分可以採用強制類型轉換(const_cast),來去掉訪問的 const 性質

強制轉換???有點奇妙

23.考慮排序vector代替關聯容器

查找操作幾乎不和插入、刪除操作混在一起

24.效率至關重要,選擇map::operator[]還是map::insert()

operator[] 先默認構造再賦值,所以單純添加內容優先選擇 insert()

26. iterator 優先於其他迭代器

27.const_iterator 轉換成 iterator

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
std::vector<int> v = {1, 3, 5};

typedef std::vector<int>::iterator It;
typedef std::vector<int>::const_iterator CIt;

int main()
{
    CIt ci = v.begin();
    It i = v.begin();
    std::advance(i, std::distance(i, ci));
    std::cout << *i << "\n";
    return 0;
}

上述代碼無法通過編譯,distance 的兩個參數需是同一類型

解決方法是指明參數類型 std::advance(i, std::distance<CIt>(i, ci));

28.reverse_iterator 的 base() 成員函數產生的 iterator 用法

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>



int main()
{
    std::vector<int> v;
    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    std::vector<int>::reverse_iterator ri = std::find(v.rbegin(), v.rend(), 7);
    std::vector<int>::iterator i(ri.base());

    std::cout << *ri << "\n";
    std::cout << *i << "\n";

    return 0;
}

base() 函數返回底層迭代器,指向 reverse_iterator 當前指向的下一個元素

http://upload.cppreference.com/mwiki/images/3/39/range-rbegin-rend.svg

如果在 ri 的前面插入一個元素,和在 ri.base() 前面插入一個元素的邏輯是一樣的。

insert() 和 erase() 函數不接受 reverse_iterator 作爲參數,需要使用 iterator。

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>



int main()
{
    std::vector<int> v;
    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    std::vector<int>::reverse_iterator ri = std::find(v.rbegin(), v.rend(), 7);
    std::vector<int>::iterator i(ri.base());

    std::cout << *ri << "\n";
    std::cout << *i << "\n";
    
    v.erase(--i);
    for (int x : v) {
        std::cout << x << "\n";
    }
   
    return 0;
}

v.erase(–i);//應該是編譯不過的,但是我編過了

但是中間解釋不太懂

v.erase((++ri).base());//應該這樣用

29.istreambuf_iterator

int main()
{
  ifstream input_file("int.txt");
  string file_data((istreambuf_iterator<char>(input_file)), istreambuf_iterator<char>());

}

30.確保區間足夠大

transform

transform(v.begin(), v.end(), res.end(), [](int x){return x;});//無效對象的賦值操作

生成迭代器

transform(v.begin(), v.end(), back_inserter(res), [](int x){return x;});

  1. back_inserter 返回的迭代器調用 push_back()
  2. front_inserter 返回的迭代器調用 push_front()
  3. inserter 把結果插入到特定位置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章