effective stl学习笔记

术语:高内聚低耦合功能独立,接口清晰,结构体定义规范,效率高,可扩展性可移植性可兼容性可维护性优良

标准stl序列容器:vector,string,deque和list

标准stl关联容器:set,multiset,map,multimap

非标准序列容器:slist单项链表,rope重型string

非标准关联:hash_set,hash_multiset,hash_map,hash_multimap

标准非stl: 数组,bitset,valarray,stack,queue和priority_queue


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

如果要写下new T[...];就意味着你要承担以下责任:要delete,否则资源泄露,要用合适的delete,delete[],否则结果不确定,只能delete一次,多次delete也是不确定的。

所以每当你想要动态分配数组的时候都要考虑用vector和string替代(一般用vector,只有当T类型为char的时候用string,但是当string运用于多线程环境下,基于引用计数的string会造成额外的同步消耗,因为string使用引用计数可以不必要的内存分配和不必要的字符复制,从而提高程序效率,如此重要以至成为标准,但在多线程中要加入同步机制,抵消性能提升,这时候要用vector<char>,也可以考虑禁止string的引用计数,通常改变某个预处理变量的值,or寻找一个不依靠引用计数实现的string的实现或者部分实现)。


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

stl会自动增长以容纳所有数据(只要没达到最大限制,最大限制查询成员函数 max_size()),增长过程:调用类似realloc的操作,分四步,1、分配一个更大的内存,vector和string是以2倍增长的,2、旧内存元素复制到新内存元素,3、析构掉旧内存的元素,4、释放旧内存。这四步消耗时间,而且每当这些步骤发生的时候,所有指针,迭代器和引用都将无效,如果某些数据结构用到这些元素的指针,迭代器和引用,那将变得很麻烦。

vector<int > vec;

for(int i = 0; i<1000; i++) v.push_back(i);

上述代码会重新分配10次

vector<int > vec;

vec.reserve(1000);

for(int i = 0; i<1000; i++) v.push_back(i);

因为2的十次方等于1000所以尽早分配1000内存,避免重新分配

所以如果确切知道大概有多少元素,那么可以尽早分配,若不知道,那么分配足够大的,之后移除多余部分

易混函数:size()多少元素 capacity()多少容量 resize(n)强制改变到含有n个元素的状态,比size大则默认构造函数构造,比size小,析构末尾,比capacity大,重新分配。reserve(n)强制改变容量,如果比当前capacity小的话vector不理会,string容器容量变为size和n的最大值,可以达到移除多余容量的目的,但是还有更好的swap方法


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

sizeof(string)是多少?不同的实现有不同的结果,有的时候与char*同样大,有的时候是char *的1到7倍大。因为string要包含字符串大小,字符串容量,字符串的值,【它的分配子的副本】,【引用计数】这些信息的不同组织方式构成了string实现的多样性

1、string可能实现引用计数,用过修改预处理宏来改变配置,关闭,引用计数可以在频繁复制的时候增加性能

2、string大小是指针的1到7倍

3、创建一个新的string可能动态分配0,1,2次内存

4,不同的实现对最小分配单位有不同的策略

5、string可能共享也可能不共享大小和容量信息

6、string可能支持也可能不支持对单个对象的分配子


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

vector和string的使用能避免编程的常犯错误并且可以充分运用stl算法的威力,但是现在有很多旧的api使用数组和char*

如果vector里面有值那么 ,就是vector首元素的地址,就是长度,可以代替fun(int *a, int len)

if(!v/empty())

{

fun(&v[0],v.size());

}

注意迭代器不是指针,要用&*v.begin()实现上述替换


对于string使用fun(s.c_str());

利用c的api初始化vector和string

vector<int > v(max_size);

v.resize(fun(&v[0],v.size()))

如果你要处理一个string那么也先存到vector然后再用区间构造函数初始化string,因为string和数组的内存布局不同,

事实上,把capi的数据写入vector再传给其它stl都是可行的,

把stl传入capi也通过vector来实现


第十七条:使用swap技巧除去多余的容量


vector的元素太多了,要使用其中的一部分,首先用部分排序选出一部分,然后erase,但是erase只是把元素删除,但是容量没有变化。

swap:vector<int>(s).swap(s);   vector<int>(s)表示用复制构造函数创建了一个临时vector,这个临时vector里面只有有用的元素,然后临时vector和vector互换,然后临时vector析构。string也可以用同样的方法实现。如果和默认构造函数交换,那么可以使容器变为当前实现下的最小值vector<int>().swap(s); 


第十八条:避免使用vector<bool>


因为在vector中bool是连续存储的每个bool只占据一个二进制位,所以表现的好像是存在容器里面但是并不是,所以很多方法用不了,是个失败的使用,用deque<bool>和bitset替代它




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值