Effective STL 章节(一)
——50条有效使用STL的经验(5/50)
文章目录
- Effective STL 章节(一)
- 第一条、慎重选择容器类型
- 第二条、不要试图编写独立于容器类型的代码
- 第三条、确保容器中的对象拷贝正确而高效
- 第四条、调用empty而不是检查size()是否为0
- 第五条、区间成员函数优于与之对应的单元素成员函数
第一条、慎重选择容器类型
标准STL序列容器:vector、string、deque和list
标准STL关联容器:set、multiset、map和multimap
非标准的关联容器:hast_set、hash_multiset、hash_map和hash_multimap,存在变体
要注意这些容器可以分为:连续内存容器 和 基于节点的容器
请参考从零开始手写STL,里面会详细介绍各个容器的实现与代码
第二条、不要试图编写独立于容器类型的代码
举例:deque
和vector
都有函数push_back
,有的代码员想要构建一个通用的push_back
函数来实现多个容器的插入
结论是没必要,因为容器都是特殊的,这样写并不会提高什么效率
可行的方法是:
// 使用typedef来控制
typedef std::vector<Test> TestContainer;
...
TestContainer cw;
Test testone;
cw.push_back(testone);
此时把vector更换为deque一样可以工作
// 使用typedef来控制
typedef std::deque<Test> TestContainer;
...
TestContainer cw;
Test testone;
cw.push_back(testone);
但是依然不建议,最好还是一开始就想清楚用什么容器,不要中途换
第三条、确保容器中的对象拷贝正确而高效
STL的容器在进行插入动作时,一般是先复制对象,再放入容器,所以存进容器的是复制品
参考从零开始手写STL对Vector的实现,在插入时会进行拷贝
这里又会出现什么问题呢?举例:
vector<Father> vw;
class son:public Father{...};// son 是Father类的派生,除了Father的元素,还额外有自己的元素son sw;
vw.push_back(sw); // 将son加入到Father的vector中,会导致丢失son独有的元素
这种情况的解决方法是:建议使用指针,即vector<Father *> vw
但是以一个C++程序员的经验来讲,拷贝指针是一件很敏感的事情,实际上如果把模板设置成auto_ptr
,编译是不会通过的
所以这条经验的核心思想是:请你注意拷贝的时候,类和类是对应的,别丢东西
第四条、调用empty而不是检查size()是否为0
虽然这两者在代码功能上没有区别,但是在某些特殊情况下,检查size会更慢,而empty总是花费常数时间,所以听吧
第五条、区间成员函数优于与之对应的单元素成员函数
这句话有点长,拆分一下
“区间成员函数”:是一种成员函数,使用两个迭代器参数来确定操作所执行的区间
这么讲可能还是有点迷糊,举例:
int myints[]={10,20,30,40,50,60,70};
std::vector<int> myvector (7);
std::copy ( myints, myints+7, myvector.begin() );
这里的copy就是区间成员函数,它按照给定的迭代器来确定执行区间,类似的有assign、insert、remove等
“单元素成员函数”:每次执行只针对一个元素的函数
实际上就是把上面的代码变成:
int myints[]={10,20,30,40,50,60,70};
int myints[] = {10, 20, 30, 40, 50, 60, 70};
std::vector<int> myvector;
for (size_t i = 0; i < 7; ++i) myvector.push_back(myints[i]);
这里push_back就是单元素成员函数
所以这条经验的意思是:尽量能用一行解决的事情,不要写一个循环去弄
为什么呢?
举例:用insert,既可以进行区间插入,也可以在循环里一次插入一个
// 区间函数
v.insert(v.begin(), data, data + n);// 单元素函数
for(int i = 0; i < n; i ++)v.insert(v.begin() + i, data[i]);
1、很明显加入循环的话,会多调用n-1次insert函数,这个是有可能耗时的
2、对于insert
这个函数,每次插入都会使得插入位置后面的元素向后移动,所以用单元素时要额外移动n-1次,明显耗时
3、考虑list这种链表类型的数据,套用循环的插入和删除,会额外增加n-1次指针的赋值,但是压根没必要
所以:能用区间函数就用区间函数,干净、简洁、高效