Effective STL学习

引言

以下为个人的一些读书心得,对于部分比较浅显易懂的就不再赘述,只是日常使用中不太会留意到的加以解释。

第一章 容器

第一条:慎重选择容器类型

第二条:不要试图编写独立于容器类型的代码

第三条:确保容器中的对象拷贝正确而高效

第四条:调用empty而不是检查size()是否为0

举例:list的size()可能需要遍历整个链表才能得到,而empty却不需要。

第五条:区间成员函数优先于与之对应的单元素成员函数

比较三种形式:
1.

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

2.

vector<Widget> v1, v2;
...
v1.clear();
for (vector<Widget>::const_iterator ci = v2.begin() + v2.size()/2; ci!= v2.end(); ++ci) {
    v1.push_back(*ci);
}

3.

vector<Widget> v1, v2;
...
v1.clear();
copy(v2.begin() + v2.size() / 2, v2.end(), back_inserter(v1));

比较三种形式,2,3比较类似(3的内部实现几乎和2相同,故合并讨论,仅讨论1和2的区别)。
书中讲了三点:a.多次对insert的调用(这个我认为几乎可以忽略);b.针对于当前例子,针对v1多次的push_back可能导致vector容量多次增加,而通过区间成员函数会一次性增加到所需容量;c.insert或者push_front比较明显,每次调用均会导致后面内容的移动,而通过区间成员函数几乎总可以一次性移动到位。

最后书中给出了几种区间函数:
1. 区间创建 container::container(InputIterator begin, InputIterator end);
2. 区间插入 void container::insert(iterator position, InputIterator begin, InputIterator end);
3. 区间删除 iterator container::erase(iterator begin, iterator end);// 序列容器 void container::erase(iterator begin, iterator end);// 关联容器 // 这些不同导致在循环中删除容器元素的区别,在后面条例中也有提及,这里支出关联容器不返回一个迭代器是由于这样操作将导致不可接受的性能负担,对此作者也不甚赞同。
4. 区间赋值 void constainer::assign(InputIterator begin, InputIterator end);

第六条:当心c++编译器最烦人的分析机制

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());

虽然这段代码当使用到data时即会报错,但是还是可以分析下以上代码被解析的语义:
istream_iterator(dataFile), istream_iterator()将被解析为两个参数(第一个参数名为dataFile,第二个参数名进行了省略);
类似:int f(double (d)); <==> int f(double d);
最终可以将istream_iterator(dataFile)通过“()”包裹即可

第七条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构钱江指针delete掉

第八条:切勿创建包含auto_ptr的容器对象

第九条:慎重选择删除元素的方法

以下附上了书中的总结,其中第三条需要注意下,这个也可以参见条例五区间删除。
这里写图片描述

第十条:了解分配子的约定和限制

这条在定制allocator时需要注意

第十一条:理解自定义分配子的合理用法

第十二条:切勿对STL容器的线程安全性有不切实际的依赖

第二章 vector和string

第十三条:vector和string优先于动态分配的数组

第十四条:使用reserve来避免不必要的重新分配

第十五条:注意string实现的多样性

//TODO 有空可以多查看下各种知名的实现,或者参照书中提出的自己实现一下

第十六条:了解如何把vector和string数据传给旧的API

  1. vector传递给指针: &vd[0],vector在c++标准中保证了它和数组内存上保持一致(注意不要使用vd.begin(),因为没有强制要求vector迭代器的就采用指针实现);
  2. string s; s.c_str();
  3. string,set,list需要采用c api均可以通过vector传递,在通过assign进行转换。(注意:vector通过c api填充值后需要重新resize
    这里写图片描述

第十七条:使用“swap技巧”出去多余容量

// 使容量最小
vector<Contestant> v;
string s;
...
vector<Contestant>(v).swap(v);
string(s).swap(s);
// 清空并使容量最小
vector<Contestant> v;
string s;
...
vector<Contestant>().swap(v);
string().swap(s);

第十八条:避免使用vector

由于vector进行了优化,内部使用bit进行存储,所以vector::operator[]返回和其它vector有所不同,书中建议避免使用,本人对此知识有限,当遇到它的弊端再详细探讨。

第三章 关联容器

第十九条:理解相等和等价的区别

这个主要对于关联容器中的插入,因为关联容器要要排序(考虑set),插入一个对象,总能考虑是在参考节点前面还是在后面(这种通过operator<或者是用户定义的判别式进行判断),如果a,b: a < b == false && b < a == false则a、b等价,则ab不能同时插入进set,所以是否等价为插入的唯一标准
但有时候等价和相等并不一致:如果set中插入元素判别式不区分大小写,而元素相等需要精确匹配。则A、a不能同时插入进set,而且set的find采用等价规则(注意和std ::find采用相等规则,两者可能出现不太一致的现象),举例:
这里写图片描述

第二十条:为包含指针的关联容器指定比较类型

今天到此为止,后期继续添加

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值