條目十四《使用reserve來避免不必要的重新分配》
阿新 • • 發佈:2019-01-12
條目十四《使用reserve來避免不必要的重新分配》
使用vector和string的插入元素的時候,我們是不用擔心記憶體問題的(只要不超過容器的max_size)。因為底層有分配子管理記憶體。在插入元素的時候,記憶體不夠會發生像realloc的過程:
- 分配新的記憶體塊,它有容器目前容量的幾倍。在大部分實現中,vector和string的容量每次以2為因數增
長。也就是說,當容器必須擴充套件時,它們的容量每次翻倍。- 把所有元素從容器的舊記憶體拷貝到它的新記憶體。
- 銷燬舊記憶體中的物件。
- 回收舊記憶體
先看個例子
vector<int> vec; for(int i = 0; i < 10; i++) { vec.push_back(i) }
這個過程會發生最少4次重新分配記憶體的過程。再來看下一個重新分配記憶體涉及到哪些過程:
- 1.new操作-->malloc
- 2.拷貝操作
- 3.析構物件
- 4.釋放記憶體
咋一看,一兩次還可以接受,當插入的元素越來越多的時候,對效能的消耗是非常客觀的。
上面的問題還只是其中一個問題,在插入元素時,重新分配記憶體會造成迭代器、指標和引用的失效。
為了優化這兩個問題,在使用vector和string的時候,可以使用reserve函式。先引出四個關於容器大小和設定的成員函式:
size()———————獲得容器的元素個數
capacity()———獲得容器的容量
resize()—————強制設定容器的元素個數(引數大於當前大小,呼叫預設建構函式建立元素填充在尾部。小於當前大小,會析構並銷燬多餘的元素)
reserve()————強制設定容器的容量大小(引數小於現有的容量大小會忽略當前呼叫,大於會擴容。)
為了避免容器的不必要擴容而造成的消耗,在初始化容器的時候可以通過reserve()設定容器的容量大小,這樣在插入元素的是夠,只要當前的元素個數小於容量大小,都不會發生重新分配記憶體。這樣也就不會發生迭代器、指標和引用失效等問題,也就沒有多次拷貝,析構物件,釋放記憶體的現象發生。
vector<int> vec; vec.reserve(15); for(int i = 0; i < 10; i++) { vec.push_back(i) }
這個過程在reserve後插入元素不會發生重新分配記憶體過程。因為,插入的元素個數(10)小於容量的大小(15)。
可能有人說,在開始時設定過多的容量,那麼不就相當於陣列嗎?浪費了剩餘沒用到記憶體,不用擔心這個問題,我們可以等插入元素完畢的時候:
- 呼叫sesize()來修剪大小
- 使用swap()技巧。(vector