标签:
vector容器迭代器(一)里面大牛对vector介绍的已经很详细了,下面结合自己的项目开发的问题谈谈使用
在下想用数组引用的方式遍历vector中的元素,结果一直采用capacity,最后的结果就是总是出错,查了半天才知道原来这个capacity是只扩不收的,我因为
需要删除了vector(采用erase,第三部分)中的数,但是capacity没有更新,结果我按照capacity的指示寻找元素,明显就会越界
[1]
---->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)”函数则会先进行越界的判断,例如下面两断程序:
程序一:
vector<int> v;
v.reserve(2);
v[0]=1;
cout << v[0] << endl;
程序二:
vector<int> v;
v.reserve(2);
v.at(0)=1;
cout << v.at(0) << endl;
两段程序编译都正常,执行时程序一会输出1。这是一个很危险的动作,因为v[0]这块内存还是“野”的。而程序二则会收到一条“std::out_of_range”异常,因为“at(size_type)”函数会进行进行下标越界的检查,来保证程序的安全。此时vector的size()为0,其中并没有对象,所以对第0个对象的访问是越界的。
结合下面的程序可以更入的理解程序一中的问题。
程序三:
vector<int> v;
v.reserve(2);
v[0]=1;
cout << v[0] << endl;
v.reserve(3);
cout << v[0] << endl;
输出结果是
1
-842151451
原因很简单,虽然reserve(2)使vector容量扩展成至少为2,但是这些空间都是空的,也就是v[0]还是一块“野”内存。所以在使用reserve(3)扩展capacity时,得到的新空间里什么都没有。
总结:
1. operator[]和at()只能支改动那些确实存在于容器中的元素,不能自动使容器产生新元素。
2. at()提供了越界检查的功能,使用起来更安全,同时比起operator[]来代价也更大。
3. reserve()只能扩展容器的capacity,不会在其中加入元素。对于reserve()扩展的空间,可以使用push_back(const T&)来填入对象。
首先给出一段代码:
35 void testvector()
36 {
38 vector v;
39 v.push_back(1);
40 v.push_back(2);
41 cout << "v size = " << v.size() << " v capacity = " << v.capacity() << endl;
42 v.erase(v.begin());
43 cout << "v size = " << v.size() << " v capacity = " << v.capacity() << endl;
44 vector(v).swap(v); // 清除v而且最小化它的容量
45 cout << "v size = " << v.size() << " v capacity = " << v.capacity() << endl;
47 }
结果如下:
[hfx@didkey1 bin]$ ./test
v size = 2 v capacity = 2
v size = 1 v capacity = 2
v size = 1 v capacity = 1
分析:
可以清楚地看到这个问题,在第一次 v.erase(v.begin());的时候,并没有真正释放删除元素的内存,它的容量还是存着。我也简单描画下这个生活中的问题——
你拿这一个1000升的水去沙漠上旅行,开始是满的,但是,你的旅途让你的水变成了1升,而且路途中,你没有水资源让你再次灌满,那么,你一直将拖着一个1000升
容量的大水箱,载着1升水在旅行,你是不允许自己这样做的。你只有把这个水箱切了,切成10升或者1升,小点……
vector也一样,你把水喝了,并不能把水箱也缩小,要把水箱缩小的做法——
——swap()交换函数完美释放内存。
vector(v).swap(v); // 清除v而且最小化它的容量
注意:
a. erase()函数,只能删除内容,不能改变容量大小;
erase成员函数,它删除了itVect迭代器指向的元素,并且返回要被删除的itVect之后的迭代器,迭代器相当于一个智能指针。
b. clear()函数,只能清空内容,不能改变容量大小
c. vector容器删除不自动释放内存,那么它存在内存泄露???不是的,vector在析构函数的时候,对内存进行了释放。
d. 如果要想在删除内容的同时释放内存,那么你可以选择deque容器。
e. 关于vector:
vector相当于c++中的数组,数组在初始化的时候也需要给它一个数组空间大小,vector申请的时候将预留一个空间,比如10,在元素超过10的时候,vector自动将大小
扩大到两倍,并且将元素拷贝过去。
vector::erase():从指定容器删除指定位置的元素或某段范围内的元素
vector::erase()方法有两种重载形式
如下:
iterator erase(
1.iterator
如果是删除指定位置的元素时:
返回值是一个迭代器,指向删除元素下一个元素;如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;
首先我先把MSDN上的例子po上来
Output
v1 = 10 20 30 40 50
v1 = 20 30 40 50
v1 = 20 50
大家可以知道,需删除元素10只要指定该元素对应的迭代器传给erase就OK了;
那现在如果该容器中有两个元素10要怎么删除呢?
接着我做下修改,向容器中添加一新的元素10
大多数初学者在不熟知erase的原理的时候,也会像我一样这样处理,
一一遍历容器找到元素值为10,然后一一删除
当试着重新build程序后运行,会出现包含有如下信息的错误
_Myptr < ((_Myvec *)(this->_Mycont))->_Mylast
其他出现这种原因是没搞懂erase的原理,当调用erase()后Iter迭代器就失效了,变成了一野指针。
所以要处理这种问题,关键是要解决调用erase()方法后,Iter迭代器变成野指针的问题,
这个时候呢给他赋一个新的迭代器给他。
重新Iter迭代器指定下一个元素.
上面那种方法是给Iter重新赋于新v1的begin迭代器。
还有一种方法是直接赋删除元素的下一个迭代器给Iter
实现方法的代码如下:
*感谢各位博主!
参考文献:【2】http://www.cnblogs.com/viviman/archive/2012/10/29/2775104.html
【3】http://blog.sina.com.cn/s/blog_6377b8e60100ino6.html
【4】http://blog.csdn.net/dgyanyong/article/details/21268469
标签:
原文地址:http://blog.csdn.net/junshen1314/article/details/44985979