迭代器
標準STL容器提供了四種不同的迭代器:
iterator门坷、const_iterator暗赶、reverse_iterator和const_reverse_iterator
條款26:盡量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator
每個標準容器類都提供四種迭代器類型。對于container<T>而言淤翔,iterator的作用相當于T*,而const_iterator則相當于const T*佩谷;
增加一個iterator或者const_iterator可以在一個從容器開頭趨向尾部的遍歷中讓你移動到容器的下一個元素旁壮。reverse_iterator與const_reverse_iterator同樣相當于對應的T*和
const T*,所不同的是谐檀,增加reverse_iterator或者const_reverse_iterator會在從尾到頭的遍歷中讓你移動到容器的下一個元素抡谐。
迭代器使用的一個重要指導方針是:盡量使用iterator代替其他三種迭代器,原因有:
- insert和erase的一些版本要求iterator桐猬。如果你需要調(diào)用這些函數(shù)麦撵,你就必須產(chǎn)生iterator,而不能用const或reverse iterators溃肪。
- 不可能把const_iterator隱式轉換成iterator免胃。
條款27:用distance和advance把const_iterator轉化成iterator
如果你只有一個const_iterator,而你要在它所指向的容器位置上插入新元素呢惫撰?也就是如何把const_iterator轉化為iterator呢羔沙?前面提到:并不存在從const_iterator到iterator之間的隱式轉換,也就是說下面操作是不可以的:
typedef deque<int> IntDeque;
// 方便的typedef
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
ConstIter ci;
// ci是const_iterator
...
Iter i(ci);// 錯誤厨钻!沒有從const_iterator 到iterator隱式轉換的途徑
Iter i( const_cast<Iter>(ci)); // 仍是個錯誤扼雏!不能從const_iterator映射為iterator坚嗜!
正確方法如下:
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
...
// 讓ci指向d
Iter i(d.begin());
// 初始化i為d.begin()
advance(i, distance <ConstIter> (i, ci));
// 把i移到指向ci位置
注:distance返回兩個指向同一個容器的iterator之間的距離;advance則用于將一個iterator移動指定的距離呢蛤。如果i和ci指向同一個容器惶傻,那么表達式advance(i, distance(i, ci))會將i移動到與ci相同的位置上棍郎。
5其障、算法
條款30:確保目標區(qū)間足夠大
目標區(qū)間不會進行內(nèi)存檢查,也不會動態(tài)擴充內(nèi)存涂佃,所以要提前估算目標區(qū)間的內(nèi)存大小励翼,也可以使用插入迭代器。
條款31:了解你的排序選擇
(1) 如果你需要在vector辜荠、string汽抚、deque或數(shù)組上進行完全排序,你可以使用sort或stable_sort伯病。
(2) 如果你有一個vector造烁、string、deque或數(shù)組午笛,你只需要排序前n個元素惭蟋,應該用partial_sort。
(3) 如果你有一個vector药磺、string告组、deque或數(shù)組,你需要鑒別出第n個元素或你需要鑒別出最前的n個元素癌佩,而不用知道它們的順序木缝,nth_element是你應該注意和調(diào)用的。
(4) 如果你需要把標準序列容器的元素或數(shù)組分隔為滿足和不滿足某個標準围辙,你大概就要找partition或stable_partition我碟。
(5) 如果你的數(shù)據(jù)是在list中,你可以直接使用partition和stable_partition姚建,你可以使用list的sort來代替sort和stable_sort矫俺。如果你需要partial_sort或nth_element提供的效果,你就必須間接完成這個任務
條款32:如果你真的想刪除東西的話就在類似remove的算法后接上erase
先看一個錯誤的實例:
// 建立一個vector<int> 用1-10填充它
vector<int> v;
v.reserve(10);
for(int i = 1; i <= 10; ++i) {
v.push_back(i);
}
cout << v.size();
// 打印10
v[3] = v[5] = v[9] = 99;
// 設置3個元素為99
remove (v.begin(), v.end(), 99);
// 刪除所有等于99的元素
cout << v.size();
// 仍然是10桥胞!
正確的刪除元素的方法是:
vector< int> v;
// 正如從前
v.erase( remove (v.begin(), v.end(), 99), v.end());
// 真的刪除所有等于99的元素
cout << v.size();
// 現(xiàn)在返回7
需要注意的是remove和erase是親密聯(lián)盟恳守,這兩個整合到list成員函數(shù)remove中。這是STL中唯一名叫remove又能從容器中除去元素的函數(shù):
list<int> li;
// 建立一個list
// 放一些值進去
li.remove(99);
// 除去所有等于99的元素:真的刪除元素贩虾,所以它的大小可能改變了
remove_if 催烘,unique和remove
類似,都需要跟erase連用才可以真正刪除數(shù)據(jù)缎罢,同樣伊群,對于list是個特殊考杉。
條款33:提防在指針的容器上使用類似remove的算法
該條款是對條款32的補充,采用remove/erase方式刪除指針容器中的數(shù)據(jù)會造成內(nèi)存泄漏舰始, 正確的方法有兩種:
(1)在應用erase-remove慣用法之前先刪除指針并設置它們?yōu)榭粘缣模缓蟪ト萜髦械乃锌罩羔槪?br>
(2)采用智能指針,如boost庫中的shared_ptr和scoped_ptr
條款34:注意哪個算法需要有序區(qū)間
STL中只能操作有序數(shù)據(jù)(升序)的算法有:
(1) binary_search:二分查找
(2) lower_bound:下界
(3) upper_bound:上界
(4) equal_range:所有等于某個值的元素
(5) set_union:集合并集
(6) set_intersection:集合交集
(7) set_difference :集合差集
(8) set_symmetric_difference:包含在第一個集合但是不包含在第二個集合中的元素丸卷,包含在第2個集合但是不包含在第1個集合中的元素
(9) merge:合并兩個有序表
(10) inplace_merge:合并兩個有序表
(11) includes:檢測一個區(qū)間的所有對象是否在另一個區(qū)間中
另外枕稀,下面的算法一般用于有序區(qū)間,雖然它們不要求:
(12) unique:去重谜嫉,相同的元素必須緊挨著萎坷,排序是個特例
(13) unique_copy:同上
原創(chuàng)文章,轉載請注明: 轉載自董的博客
本文鏈接地址: http://dongxicheng.org/cpp/effective-stl-part3/