還是很喜歡effective部分的書,看了好幾遍,這裡把stl中和容器相關的一些基本的注意的點進行介紹總結,之後對迭代器等進行總結
1 對序列容器中需要逐個刪除的時候,不能像關聯容器那樣事先對迭代器進行++操作,因為刪除乙個迭代器,會使他自己無效,後面的迭代器也無效,所以應該儲存刪除erase返回的下乙個指標的值。而關聯容器中並不會導致後面的迭代器無效的情況
2 在stl中如果對容器內物件使用了new操作,一定要釋放掉,因為析構函式沒辦法完成,這裡最好使用智慧型指標,但是不要使用auto_ptr的指標,因為他的拷貝,會使背被拷貝的物件賦值為null可能導致無法預料的問題
3 如果希望減少在替換容器的型別的時候需要修改的**,那麼應該把容器進行typedef的替換,同時最好直接隱藏到乙個類當中,進行使用介面進行處理
4 使用區間成員函式,比如assign,區間的建構函式,區間的insert函式,區間的erase函式,都能比迴圈呼叫單元素對應的函式好,從函式呼叫,元素之間賦值位置變化,還有記憶體的分配問題進行考慮
5 對於序列容器,list容器,還有關聯容器,刪除元素的使用應該選用不同的刪除函式,具體參見條款9,注意這裡是刪除某個單獨的元素,如果是直接刪除乙個區間的資料,那麼直接利用erase就可以
6 許多string的背後使用了計數的功能,消除沒有必要的記憶體分配和字元拷貝,提高了效率。但是如果是在多執行緒的情況下,那麼久必須注意讀寫的一致性問題
7 reverse函式只有vector和string有
他可以減少記憶體重新分配的次數
重點需要區分一下resize和reverse兩個函式
resize:強迫容器改變到包含n個元素的狀態,如果比現在的size()數量小,那麼將末尾的資料析構,如果大那麼利用預設建構函式進行初始化
reverse:強迫容器的容量為n,和capacity()進行對應,通常導致新的記憶體分配。如果n比當前的容量小,vector什麼都不做,string將其設為size()和n中的最大值
一般在宣告容器後就進行reverse的操作,可以預見大小的情況下,之後也就可以預估迭代器是否會失效
8 string有很多的實現方式
但是基本都必須存有下面幾個部分的資料
字串的大小
記憶體的容量capacity
字串的值
分配子的乙個拷貝
對值的引用計數
不同的實現方式可以會使器是否有引用計數,經常需要複製,或者多執行緒的情況下可能有用,同時如果是小字串,是否會進行單獨的油畫,建立時候的動態分配記憶體的數量等,詳情看第15條資料
9 如果有乙個 c api的函式
void dosomething(const int* pints,size_t numints);
void dosomething(const char* pints);
對於vector可以直接傳入&v[0],一般不建議傳入v.begin()因為他畢竟是乙個迭代器,但是傳入的時候需要判斷容器是不是空的
對於string有乙個專門的函式,s.c_str(),不需要判斷是否為空
一般傳入後,最好設為唯讀模式,如果進行了增刪操作,那麼可能會直接影響了之前的容器,導致一些不可預見的影響
如果是c函式初始化容器,都可以利用vector進行乙個中間的轉存的操作,詳情見16條款
10 如果希望將vector,string中的一些多餘的容量進行刪除,erase主要是刪除了容量的大小,但是並沒有減少容量,為了壓縮到適當的大小利用swap的方法
vector(v2).swap(v2)
string s; string(s).swap(s)
先通過建立臨時變數,只會拷貝存在的元素,然後再交換
同時注意:並不是說之後的記憶體就剛好是元素的記憶體和,可能也會有一定的保留
同時:之前的迭代器和,指標,引用之類並不會失效
11 vector中最好不要使用vector的容器,因為他並不是乙個真正的容器,只是近似於乙個容器。他是沒有辦法通過operator 取位置進行操作的。因為乙個bool在實現的時候是按位進行儲存的,只占有乙個二進位制位。而為了適配[]操作,封裝了乙個介面卡返回的是乙個適配類。所以很多麻煩
如果一定要用bool的容器,那麼建議使用deque(相對於vector函式只是沒有reverse和capacity操作)和bitsize(也是緊湊儲存,事c++標準庫中的函式)
12 在關聯容器中 有兩個概念,相等和等價
非成員函式的find函式一般是利用相等,operator ==基於資料的值是否相等eaqul_to函式
非成員函式的insert操作,因為要判斷,是否有相同的key了,所以主要是對排序資料中的位置進行判斷的,在其中的等價關係主要是通過operator < 進行判斷的,less函式
每個標準容器利用使用者自己定義的key_comp進行判斷,預設的函式是less函式,可以自己設定,確定了之後只要利用成員函式進行訪問,那麼就能夠將比較進行統一了。
而且最好在和排序相關的關聯容器中使用等價的概念
因為如果相等的情況下插入兩個其實等價的資料,但是在排序的時候又沒辦法分開排序,那麼就不能按確定的方式訪問key的value值了,類似於multiset等
但是這裡主要是提到了帶排序的關聯容器,對於不是標準的關聯容器:
hash_set hash_multiset hash_map hash_multimap
這些關聯容器並不是按照排序方式進行儲存的
他們的比較函式就是equal_to
13 複習一下traits的應用
14 如果想列印乙個容器中的值,可以用copy函式講值放入乙個輸出流中
copy(ssp.begin(),ssp.end(),ostream_iterator(count,」\n」))
還有乙個需要注意的地方就是在傳入一些比較函式的時候其實傳入的需要的是乙個型別,而不是函式指標,如果是函式指標,直接宣告乙個函式就可以了。。。需要注意,如果是乙個型別
那麼一般選擇的是乙個struct型別後建立乙個函式
struct differ
呼叫的時候 setssp
15 感覺21條建議真的是很暈啊,看了幾遍才理清楚
主要是容器中雖然有乙個等價的判斷函式比如compare但是最後判斷是否是等價還有乙個外層的判斷
!(compare(a1,a2)) && !(compare(a2,a1))
如果compare函式將兩個相等的數判斷為相等,那麼最終會導致說這兩個數不等價,錯誤
所以對相等的數,compare應該返回false,其實這裡的compare應該理解為 乙個值是否在另乙個值的前面,如果兩個值相等,那麼他的值當然沒有位置的關係,所以應該返回false
16 對於set map型別中如果需要修改對應的key
在map中型別是pair,其中k是const型別,所以是不允許直接修改的
在set中元素不是const的,因為型別可能是定義的struct或者 class的型別,在排序的過程中,根據某一元素進行排序,那麼在修改的時候他是不能夠修改的,但是對於別的部分,是可以進行修改的。
因為如果直接修改,可能會影響之前的排序情況
如果一定要進行改變,最好的是複製元素,修改,刪除後重新插入
17 在考慮排序的vector的過程中:
因為map中是按照平衡二叉樹進行儲存的,如果只是想要提高查詢的速度,那麼選用雜湊的容器(常數時間)遠遠好於標準容器的對數時間,但是如果雜湊表比較小,可能會使查詢的效能比較差
同時在map的儲存中因為還有一些指標的額外開銷,同時作用兄弟在無力上的儲存也不相鄰。所以如果量很大,比如跨越了多個記憶體頁面的情況下可能會相對而言比較慢。
相對於排序的vector中,如果採用binary_search可能會更快,但是因為是vector的情況,所以必須要求資料的增刪的操作很少,同時還得模擬pair 的一些操作,這裡乙個注意的地方就是,map中的key是const的,但是在vector中進行模擬的時候是不能定義為const,因為會有很多的拷貝操作等
18 對於map的操作,操作有不同的意思,如果key在原來的資料結構中沒有,那麼對應時插入操作,如果已經有了,那麼對應的就是修改操作
為了效率高,
如果,確定知道是插入,最好利用insert操作。因為如果是,是先插入乙個建構函式對應的pair資料,然後再進行修改的資料,不如直接插入
如果是修改操作,那麼就是直接進行[],因為如果是利用insert,是先將值[]修改了後insert
Effective STL 關聯容器
在stl中有很多這樣的函式,它們需要確定兩個值是否相同,但這些函式以不同的方式來判斷這兩個值是否相同。find對相同的定義是等價的,是以operator 為基礎,而set insert對系統的定義是等價。因此需要了解它們之間的區別。在實際過程中,相等的概念是基於operator 的,如果表示式x y...
Effective STL 第一章 容器(二)
第3條 確保容器中的物件拷貝正確而高效 1,copy in,copy out是stl的工作方式,即向容器中加入物件時,存入容器的是你指定物件的拷貝,從容器中取出物件時,得到的是容器中所儲存的物件的拷貝。2,拷貝物件時stl的工作方式,當對vector,string或deque進行元素的插入或刪除操作...
《Effective STL》讀書筆記
工作之後更多地接觸到stl,在專案中stl的使用更是屢見不鮮。最近在看此書,有必要小小地總結一下。1.用empty 而不用size 0去判斷容器是否為空 從功能上看,兩者是一樣的。但效能上可能會有所差別。對於vector而言,size 其實就是end begin 因為它是連續記憶體分布,所以這樣計算...