effective stl(三)

条款二十二

切勿直接修改set或multimap的键

而map和multimap则永远别修改作为键的对象

set和multiset可使用const_cast结合迭代器来修改不用做排序的键对象的其他属性。

但最好的做法是拷贝一份,对拷贝进行修改,移除旧值,加入改变的值。

 

 

 

 

条款二十三

考虑用排序的vector代替关联容器

关联容器提供对数级的查找时间,且每个元素带来三个指针的负载,适用于无法确定要执行什么操作的情况,即有插入又有删除又有查找等。

排序的vector适用于插入,查找,删除分阶段进行的情况,因为查找时vector需要更少的换页,击中率要更高。

使用vector代替关联容器的时候不能把key设置成const类型,因为vector的操作要基于复制/移动。而且还需要额外的查找/排序用到的比较子分别接受:

(pair,pair)进行排序

(pair,key)进行查找

(key,pair)进行查找

因为并不知道使用哪种形式比较。

 

 

 

 

 

条款二十四

当效率至关重要时慎选map:[ ]与map::insert()

[ ]在插入一个 不存在的值时相当于

re = insert(pos, value());

re->second = new_val;

此时应该使用insert来避免re这个临时对象的创建。

 

当加入的元素已经存在时,insert需要:

insert(pair()).first->second = v;

即insert需要构建一个pair然后通过返回的pair中的指针来修改

而operator[ 则不必,故应当选用[ ]。

 

 

 

 

条款二十五

哈希容器(略,介于和当前的无序容器有差异)

 

 

 

 

 

条款二十六

iterator优于其他iterator

注意,这一条不再适用,应该改成可以的话就使用const_iterator,见morden effective c++

尽管如此,这一条的其他东西还是值得一看。

 

const_iterator,reverse_iterator,const_reverse_iterator,iterator均是不同的类型,而不是是否加上const修饰符的区别

其中:

const无法转换为一般iterator

reverse通过.base()函数可转换成普通的iterator

普通的iterator可以转换成const或reverse

 

 

 

 

 

条款二十七

使用distance + advance转换const_iterator到iterator

是的,我刚说const版iterator无法转换到一般的iterator,但实际上还是有些特别的手段。

假如我们拥有一个const_iterator 名为 ci

auto be(stl.begin());//创建一个一般的iterator

advance(be, distance<const_iterator>(be,ci) );

其实制作了一个新的iterator让它和ci指向同个元素,此处的distance<const_iterator>

模板参数中的cosnt_iterator必须指定,因为distance接受的必须是两个类型相同的,至少具有inputiterator能力的迭代器。否则传入两个类型不同的迭代器会影响到distance的模板类型推断。

这种方法的消耗:

对于随机访问的迭代器->常数时间

其他为线性

由于现在各种成员函数也可以接受const版本的iterator所以尽量使用const_iterator(当然如果你要改变元素的话例外)

 

 

 

 

条款二十八

正确理解base()

base()会返回一个迭代器将reverse_iterator转换成iterator,但这个迭代器并不是指向reverse_iterator指向的元素,而是内存地址中下一个元素。

这一点是为了保证insert()操作会得到同样的效果,因为reverse_iterator是反向遍历的,所以插入一个元素的时候会插入到当前元素在内存地址上的后一位,故把reverse_iterator转换成正常的iterator时需要指向下一个元素来使得insert()得到一样的效果。

故等价的删除操作为erase((++reverse_iterator).base());

erase(--(reverse_iterator.base()));意思相同,但有的平台无法通过编译。

 

 

 

 

 

条款二十九

对逐个字符的输入考虑使用istreambuf_iterator

即使用流迭代器

istream_iterator使用operator>>来读取,即执行格式化读取

istreambuf_iterator则只是逐字符读取,无需设定相应的格式,检测不同的状态。

同理适用于ostreambuf_iterator与ostream_iterator

 

 

 

 

 

条款三十

保证目标区间足够大

如transform(val.begin(),val.end(),

                     result.begin(),

                     predicate);

对val遍历调用predicate(),返回true的返回值追加到result中,若result不够大则会出错,因为对result中无效对象赋值。

当然,可以把result.begin改成back_inserter(result)或back_inserter(result,result.begin()+n)来使用插入的方式,而不是改变原来的元素值。

 

 

 

 

 

条款三十一

排序

取出前二十个排序

partial_sort(stl.begin(), stl.begin()+20, stl.end(),less);//实际功能应该叫做把stl这个容器分为三段,begin()到begin()+20为有序

取出前二十个不排序(顺序不一定)

nth_element(stl.begin(), stl.begin()+20, stl.end(), less);

以上函数和sort均为不稳定,但是sort有稳定版本stable_sort,以上排序仅对随机访问容器有效

 

partition(begin(), end(), 条件);

符合条件放在容器前部,不符合放在后部,返回一个迭代器指向第一个不符合的元素,具有stable版本,可用于list

 

对于list等可以使用成员函数sort,它是稳定的。或者把元素复制到vector或迭代器放到vector。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值