文章目錄
對於查到的相關資料做了梳理
如果一定需要實現內存動態釋放,第四條一定程度上可以滿足需求,但需要注意以下問題:
vector<std::string>(Vec).swap(Vec);
思考? 是否可以通過需要段元素首尾的迭代器來拷貝需要段的元素,再調用swap呢,這樣可能可以一定程度上減少調用erase帶來的大開銷,當然具體哪個比較划算還是根據實際情況來判斷
vector::erase() 函數在容器內元素比較多,刪除元素的代價會比較大,他會把後邊的元素移動至刪除位置,改變vector的size但是並不改變capacity,換句話說並不會釋放這些刪除元素的內存,官方說明如下:
/**
* @brief Remove a range of elements.
* @param __first Iterator pointing to the first element to be erased.
* @param __last Iterator pointing to one past the last element to be
* erased.
* @return An iterator pointing to the element pointed to by @a __last
* prior to erasing (or end()).
*
* This function will erase the elements in the range
* [__first,__last) and shorten the %vector accordingly.
*
* Note This operation could be expensive and if it is
* frequently used the user should consider using std::list.
* The user is also cautioned that this function only erases
* the elements, and that if the elements themselves are
* pointers, the pointed-to memory is not touched in any way.
* Managing the pointer is the user's responsibility.
*/
iterator
erase(iterator __first, iterator __last);
一、c++ vector clear() 方法的問題:
vector,clear()並不真正釋放內存(這是爲優化效率所做的事),clear實際所做的是爲vector中所保存的所有對象調用析構函數(如果有的話),然後初始化size這些東西,讓覺得把所有的對象清除了。
真正釋放內存是在vector的析構函數裏進行的,所以一旦超出vector的作用域(如函數返回),首先它所保存的所有對象會被析構,然後會調用allocator中的deallocate函數回收對象本身的內存。
所以,某些編譯器clear後還能訪問到對象數據(因爲它根本沒清除),在一些比較新的C++編譯器上(例如VS2008),當進行數組引用時(例如a[2]這種用法),STL庫中會有一些check函數根據當前容器的size值來判斷下標引用是否超出範圍,如果超出,則會執行這樣一句:
_THROW(out_of_range, "invalid vector<T> subscript");
即拋出一個越界異常,clear後沒有捕獲異常,程序在新編譯器編譯後就會崩潰掉。
-------------------------分割線--------------------------------------------------------------
二、vector的內存釋放:
原文地址:vector的內存釋放
vector : C++ STL中的順序容器,封裝數組
1. vector容器的內存自增長
與其他容器不同,其內存空間只會增長,不會減小。先來看看"C++ Primer"中怎麼說:爲了支持快速的隨機訪問,vector容器的元素以連續方式存放,每一個元素都緊挨着前一個元素存儲。設想一下,當vector添加一個元素時,爲了滿足連續存放這個特性,都需要重新分配空間、拷貝元素、撤銷舊空間,這樣性能難以接受。因此STL實現者在對vector進行內存分配時,其實際分配的容量要比當前所需的空間多一些。就是說,vector容器預留了一些額外的存儲區,用於存放新添加的元素,這樣就不必爲每個新元素重新分配整個容器的內存空間。
關於vector的內存空間,有兩個函數需要注意:size()成員指當前擁有的元素個數;capacity()成員指當前(容器必須分配新存儲空間之前)可以存儲的元素個數。reserve()成員可以用來控制容器的預留空間。vector另外一個特性在於它的內存空間會自增長,每當vector容器不得不分配新的存儲空間時,會以加倍當前容量的分配策略實現重新分配。例如,當前capacity爲50,當添加第51個元素時,預留空間不夠用了,vector容器會重新分配大小爲100的內存空間,作爲新連續存儲的位置。
2. vector內存釋放
由於vector的內存佔用空間只增不減,比如你首先分配了10,000個字節,然後erase掉後面9,999個,留下一個有效元素,但是內存佔用仍爲10,000個。所有內存空間是在vector析構時候才能被系統回收。empty()用來檢測容器是否爲空的,clear()可以清空所有元素。但是即使clear(),vector所佔用的內存空間依然如故,無法保證內存的回收。
如果需要空間動態縮小,可以考慮使用deque。如果非vector不可,可以用swap()來幫助你釋放內存。具體方法如下:
vector<int> nums;
nums.push_back(1);
nums.push_back(1);
nums.push_back(2);
nums.push_back(2);
vector<int>().swap(nums); //或者nums.swap(vector<int> ())
或者如下所示,使用一對大括號,意思一樣的:
//加一對大括號是可以讓tmp退出{}的時候自動析構
{
std::vector<int> tmp = nums;
nums.swap(tmp);
}
swap()是交換函數,使vector離開其自身的作用域,從而強制釋放vector所佔的內存空間,總而言之,釋放vector內存最簡單的方法是vector.swap(nums)。當時如果nums是一個類的成員,不能把vector.swap(nums)寫進類的析構函數中,否則會導致double free or corruption (fasttop)的錯誤,原因可能是重複釋放內存。標準解決方法如下:
template < class T >
void ClearVector( vector< T >& vt )
{
vector< T > vtTemp;
veTemp.swap( vt );
}
3. 利用vector釋放指針
如果vector中存放的是指針,那麼當vector銷燬時,這些指針指向的對象不會被銷燬,那麼內存就不會被釋放。如下面這種情況,vector中的元素時由new操作動態申請出來的對象指針:
#include <vector>
using namespace std;
vector<void *> v;
每次new之後調用v.push_back()該指針,在程序退出或者根據需要,用以下代碼進行內存的釋放:
for (vector<void *>::iterator it = v.begin(); it != v.end(); it ++)
if (NULL != *it)
{
delete *it;
*it = NULL;
}
v.clear();
三、vector::clear(),容器vector的clear函數詳解。:
原文地址:vector::clear(),容器vector的clear函數詳解。
最近經常用到vector容器,發現它的clear()函數有點意思,經過驗證之後進行一下總結。
clear()函數的調用方式是,vector temp(50);//定義了50個datatype大小的空間。temp.clear();
作用:將會清空temp中的所有元素,包括temp開闢的空間(size),但是capacity會保留,即不可以以temp[1]這種形式賦初值,只能通過temp.push_back(value)的形式賦初值。
同樣對於vector<vector > temp1(50)這種類型的變量,使用temp1.clear()之後將會不能用temp1[1].push_back(value)進行賦初值,只能使用temp1.push_back(temp);的形式。
下面的代碼是可以運行的。
#include <iostream>
#include<vector>
using namespace std;
int main(){
vector<vector<int>> test(50);
vector<int> temp;
test[10].push_back(1);
cout<<test[10][0]<<endl;
test.clear();
for(int i=0;i<51;i++)
test.push_back(temp);
system("pause");
return 0;
}
但是這樣是會越界錯誤的。
#include <iostream>
#include<vector>
using namespace std;
int main(){
vector<vector<int>> test(50);
vector<int> temp;
test[10].push_back(1);
cout<<test[10][0]<<endl;
test.clear();
for(int i=0;i<50;i++)
test[i].push_back(1);
system("pause");
return 0;
}
並且即使我們使用
for(int i=0;i<100;i++)
test[i].push_back(1);
都是可以的,因爲size已經被清除了。
四、vector容器刪除某些元素且釋放內存:
原文地址:vector容器刪除某些元素且釋放內存
1.size和capacity
size:
指目前容器中實際有多少元素,對應的resize(size_type)會在容器尾添加或刪除一些元素,來調整容器中實際的內容,使容器達到指定的大小。
capacity:
指最少要多少元素纔會使其容量重新分配,對應reserve(size_type new_size)會這置這個capacity值,使它不小於所指定的new_size。
所以用reserve(size_type)只是擴大capacity值,這些內存空間可能還是“野”的,如果此時使用“[ ]”來訪問,則可能會越界。而resize(size_type new_size)會真正使容器具有new_size個對象。
元素訪問方式差別
在對vector進行訪問時,如果使用“[ ]”,則會像變通數組那樣,不進行越界的判斷。
如果使用“at(size_type)”函數則會先進行越界的判斷。
2.應用
經常會用到vector中元素不再使用,需要刪除元素且釋放內存的操作,記錄如下:
iter = strVec.erase(iter);
strVec是容器名稱,iter是迭代器,刪除元素後,迭代器指向下一個元素;
vector<std::string>(Vec).swap(Vec);
將Vec的內存空洞清除;
vector().swap(Vec);
清空Vec的內存;
示例代碼:
#include"iostream"
#include"vector"
#include"string"
using namespace std;
int main() {
vector<string> strVec;
strVec.push_back("Sophia");
strVec.push_back("and");
strVec.push_back("Nemo");
strVec.push_back("are");
strVec.push_back("good");
strVec.push_back("people.");
cout << "The capacity of the original vector is: " << strVec.capacity() << endl;
for (vector<string>::iterator iter = strVec.begin(); iter != strVec.end();) {
if ((*iter) == "and")
iter=strVec.erase(iter);
else if((*iter) == "Nemo")
iter = strVec.erase(iter);
else
iter++;
}
vector<string>(strVec).swap(strVec);
cout << "After deleting two elements in the vector, now the capacity is: " << strVec.capacity() << endl;
vector<string>().swap(strVec);
cout << "After clearing, now the capacity is: " << strVec.capacity() << endl;
system("Pause");
return 0;
}