因为以前看STL源码剖析的时候,发现所执行的操做以下:html
只是简单的将末尾的finish迭代器减1后destroy。这让人产生一个疑问:假如这个vector为空了,finish=start了,finish再减1不就不在vector的内存控制范围了么。因而,我打算看一下vs2013编译器和g++编译器的源码。ios
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>c#
该源码的意思就是,在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类型的对象。this
总的来讲,pop_back的准确调用须要程序员来保证,在执行pop_back时候最好能预先作一些判断。
本身查到的三处说法的对比:
1、转自知道的答案: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后没有捕获异常,程序在新编译器编译后就会崩溃掉。
-------------------------分割线--------------------------------------------------------------
2、转自博客: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();
3、转自博客: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/acoolgiser/article/details/81018296