容器

来源:互联网 发布:mac 右键新建txt 编辑:程序博客网 时间:2024/06/10 10:51

Item 1 仔细选择你的容器

标准序列容器:vector、string、deque和list。vector是默认使用的序列类型。只有vector的内存布局兼容C。

list适用于频繁的插入和删除的情景。当大部分插入和删除发生在序列的头或尾部时,可以选择deque。

标准STL关联容器:set、multiset、map和multimap。

非标准序列容器:slist和rope。 //没有用过

非标准关联容器:unordered_set、unordered_multiset、unordered_map和unordered_multimap。

vector<char>可作为string的替代品。

排序的时候,有序的vector可代替关联容器。

其他的非STL容器:array、bitset、valarray、stack、queue和priority_queue。 //参考boost。

其中vector、deque和string连续内存容器。支持随机访问迭代器。在一个或多个内存块中保存他们的元素。rope也是连续内存容器。

list和slist是基于节点的容器。标准关联容器也是基于节点实现,典型实现是平衡树。

Item 4 用empty来代替检查size()是否为0。

对于所有容器,empty是一个常数时间的操作,但是对于list,size花费线性时间。

Item 5 尽量使用区间成员函数代替他们的单元素兄弟。

使用区间成员函数,可以输入更少的代码。

区间成员函数会使得代码更加清晰直截了当。

assign、copy、erase等。

Item 6 警惕C++最令人恼怒的解析。

ifstream dataFile("ints.dat");list<int> data(istream_iterator<int>(dataFile),// 警告!这完成的并不istream_iterator<int>());

上述代码可以解析为返回值为list<int>,参数为两个istream_iterator<int>的data函数声明。

避免此问题的办法:

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

Item 7 当使用new得指针的容器时,记得在销毁容器前delete那些指针。

template<typename T>struct DeleteObject :public unary_function<const T*, void> {void operator()(const T* ptr) const{delete ptr;}};


定义个释放对象的仿函数类。有一个const T*的参数,void返回值。

int _tmain(int argc, char* argv[]){vector<Widget*> vwp;vwp.push_back(new Widget(10,200));vwp.push_back(new Widget(20,400));for_each(vwp.begin(),vwp.end(),DeleteObject<Widget>());return 0;}

使用for_each来释放每一个new的指针。

Item 8 永不建立auto_ptr的容器。

Item 9 在删除中仔细选择。

去除一个容器中特定值的元素:

对于连续内存容器(vector、string、deque)的惯用法:remove-erase。 //注意remove并不真正的删除元素。

int _tmain(int argc, char* argv[]){vector<int> vi;vi.push_back(10);vi.push_back(20);vi.push_back(20);vi.push_back(40);vi.erase(remove(vi.begin(),vi.end(),20),vi.end());cout<<vi.size()<<endl;return 0;}

上例为删除vector<int>中值为20的元素。

如果是list,则可以直接使用list的remove方法。这是真正的删除某值的元素。

int _tmain(int argc, char* argv[]){list<int> li;li.push_back(10);li.push_back(20);li.push_back(20);li.push_back(40);li.remove(20);cout<<li.size()<<endl;return 0;}

如果是关联容器,可以直接调用关联容器的erase方法。

int _tmain(int argc, char* argv[]){set<int> si;si.insert(10);si.insert(20);si.insert(20);si.insert(40);si.erase(20);cout<<si.size()<<endl;return 0;}


去除一个容器中满足一个特定判定式的所有对象:

如果是string、vector和deque,使用erase-remove_if惯用法。

如果是list,使用list的remove_if。

如果是标准关联容器,则用remove_copy_if和swap。

各方法示例见下面代码:

bool goodValues(int x){if(x>=20)return true;return false;}int _tmain(int argc, char* argv[]){vector<int> vi;vi.push_back(10);vi.push_back(20);vi.push_back(20);vi.push_back(40);vi.erase(remove_if(vi.begin(),vi.end(),not1(ptr_fun(goodValues))),vi.end());cout<<vi.size()<<endl;copy(vi.begin(),vi.end(),ostream_iterator<int>(cout," "));cout<<endl;list<int> li;li.push_back(10);li.push_back(20);li.push_back(20);li.push_back(40);li.remove_if(not1(ptr_fun(goodValues)));cout<<li.size()<<endl;copy(li.begin(),li.end(),ostream_iterator<int>(cout," "));cout<<endl;set<int> si;si.insert(10);si.insert(20);si.insert(40);set<int> goodValSet;remove_copy_if(si.begin(),si.end(),inserter(goodValSet,goodValSet.begin()),not1(ptr_fun(goodValues)));si.swap(goodValSet);cout<<si.size()<<endl;copy(si.begin(),si.end(),ostream_iterator<int>(cout," "));cout<<endl;return 0;}

Item 12 对STL容器线程安全性的期待实现。

多个读者同时读同一容器是安全的。

对不同的容器,多个写入是安全的。

 


原创粉丝点击