《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 把结果插入到特定位置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章