一個空的vector執行pop_back操作會發生什么
由於之前看STL源碼剖析的時候,發現所執行的操作如下:
只是簡單的將末尾的finish迭代器減1后destroy。這讓人產生一個疑問:假如這個vector為空了,finish=start了,finish再減1不就不在vector的內存控制范圍了么。於是,我打算看一下vs2013編譯器和g++編譯器的源碼。
vs2013的編譯器源碼如下:
#if _ITERATOR_DEBUG_LEVEL == 2
void pop_back()
{ // erase element at end
if (empty())
_DEBUG_ERROR("vector empty before pop");
else
{ // erase last element
_Orphan_range(this->_Mylast - 1, this->_Mylast);
this->_Getal().destroy(this->_Mylast - 1);
--this->_Mylast;
}
}
#else /* _ITERATOR_DEBUG_LEVEL == 2 */
void pop_back()
{ // erase element at end
this->_Getal().destroy(this->_Mylast - 1);
--this->_Mylast;
}
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */</span>
該源碼的意思就是,在debug模式下運行,是會檢測vector是否empty的,但在release模式下不會檢測。經過測試,debug下pop_back一個空的vector會報錯,但release沒有,但是release下面,pop_back后這個vector基本上就廢了,你不能再push_back了,會報錯。因為pop_back顯然已經將vector的對象的結構破壞。
在g++編譯器下測試,其源碼如下:
void pop_back() _GLIBCXX_NOEXCEPT
{
--this->_M_impl._M_finish;
_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
}</span>
結果也是一樣的,pop_back一個空的vector會破壞整個vector對象,具體的作用就是finish迭代器失效。但有趣的是,下面的代碼可以運行:
vec.push_back(0);
vec.pop_back();
vec.pop_back();
vec[0] = 1;
cout << vec[0];</span>
原因就是,push_back插入對象是 分為申請空間和構造對象兩步,pop_back的destroy只有析構對象的作用,沒有deallocate的回收空間的作用。所以,pop_back之后,空間是沒有釋放的,vec[0]能夠執行賦值行為並輸出,但這個時候因為finish迭代器的損毀,vec已經不能執行push_back操作了。另外提一下,destroy函數在析構對象的時候,做了進一步的判斷,如果該對象存在有效的析構函數,則調用改析構函數析構之,否則什么都不做,比如int類型的對象。
總的來說,pop_back的准確調用需要程序員來保證,在執行pop_back時候最好能預先做一些判斷。
vector clear() 方法 內存釋放問題
自己查到的三處說法的對比:
一、轉自知道的答案:https://zhidao.baidu.com/question/323662520.html?qq-pf-to=pcqq.c2c#
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后沒有捕獲異常,程序在新編譯器編譯后就會崩潰掉。
-------------------------分割線--------------------------------------------------------------
二、轉自博客:https://www.cnblogs.com/summerRQ/articles/2407974.html
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<int>.swap(nums)。當時如果nums是一個類的成員,不能把vector<int>.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();
三、轉自博客:https://blog.csdn.net/hk_john/article/details/72463318
最近經常用到vector容器,發現它的clear()函數有點意思,經過驗證之后進行一下總結。
clear()函數的調用方式是,vector<datatype> temp(50);//定義了50個datatype大小的空間。temp.clear();
作用:將會清空temp中的所有元素,包括temp開辟的空間(size),但是capacity會保留,即不可以以temp[1]這種形式賦初值,只能通過temp.push_back(value)的形式賦初值。
同樣對於vector<vector<datatype> > 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已經被清除了。
轉自:https://blog.csdn.net/tangle001/article/details/47026989
https://blog.csdn.net/acoolgiser/article/details/81018296