《Effective STL》读书笔记

工作之后更多地接触到STL,在项目中STL的使用更是屡见不鲜。最近在看此书,有必要小小地总结一下。

1.用empty()而不用size()==0去判断容器是否为空

从功能上看,两者是一样的。但性能上可能会有所差别。对于vector而言,size()其实就是end()-begin(), 因为它是连续内存分布,所以这样计算size的时间复杂度是O(1)。但对于list这类非连续内存的容器来说,只能通过遍历整个容器来获得它的size,算法复杂度为O(n)。而empty()则是通过在容器的开头记录一个flag,只要简单查询这个flag的值,就知道容器是否为空。

那么问题来了,为什么list不能让size()在O(1)内完成呢?其实是可以的。但是,list的底层结构是链表,约定俗成的习惯是链表的增删操作是O(1)的,这样size()就只能委屈一下了,变成了线性时间操作,每次增删元素,我们可能在O(1)内完成,但size()就必须遍历链表了。

另外,既然知道size()不一定是轻量级的,那么我们在写for循环的时候(尤其是遍历list),可以考虑把size_t size = list::size()这句放在循环体的外面,这样我们就不用每次迭代都去计算重量级的size()了。但其实好多人还是会写for(size_t i = 0; i < list::size(); ++i) ... 这样的代码,为什么呢?可以少写一行,增加可读性么?这种性能开销相对于可读性来说也太大了吧。


2.使用reserve来避免不必要的内存重新分配

当容器的capacity不够了,就会申请多一倍的内存,然后把数据全部拷过去。申请新内存,拷贝,释放旧内存,这三步操作是很耗时间的。所以如果我们预先能知道容器的大概capacity,就可以用reserve来预留空间,减少了内存不必要的reallocate。例如以下两段代码,性能差别很大。

vector<int> v;
for (int i = 1; i <= 1000; ++i) v.push_back(i);

vector<int> v;
v.reserve(1000);
for (int i = 1; i <= 1000; ++i) v.push_back(i);

好像显得我太罗嗦了,这样写下去永远都写不完,明天再写,简短一点。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值