push_back的作用是在vector的末尾添加一个新元素。val的内容被复制(或移动)到新元素。
这有效地将容器大小增加1。当且仅当新的vector大小超过当前vector容量时,会重新自动分配新的存储空间。
Tips:
push_back操作demo1:
//code1 #include <iostream> #include <vector> using namespace std; #define MAX_NUM 9 int main(){ vector<int> vecInt; for(int i = 0; i != MAX_NUM; i++){ vecInt.push_back(i); } /** some code */ vecInt.push_back(123); for(int i : vecInt){ cout << i << " "; } return 0; } // 0 1 2 3 4 5 6 7 8 123
以上代码先声明了一个存放int类型的vector,然后把i递增push_back到vecInt中。之后再添加一个元素到123到vecInt中。
push_back操作demo2:
iterator遍历vector
//code2 #include <iostream> #include <vector> using namespace std; #define MAX_NUM 9 int main(){ vector<int> vecInt; for(int i = 0; i != MAX_NUM; i++){ vecInt.push_back(i); } vector<int>::iterator iter = vecInt.begin(); cout << "the 1st element: " << *iter << endl; vecInt.push_back(123); while(iter != vecInt.end()){ cout << *iter << " "; iter++; } return 0; } /* the 1st element: 0 0 1 2 3 4 5 6 7 8 123 */
在用for进行vector的push_back之后,初始化了一个iterator指向vecInt的begin位置,并打印验证。之后再用push_back在vector的末尾添加一个元素123,这时再用iter来遍历vecInt。
push_back操作demo3:
下面对MAX_NUM进行修改,将其改为8
//code3 #include <iostream> #include <vector> using namespace std; #define MAX_NUM 8 //MAX_NUM修改为8,其余地方不做任何修改 int main(){ vector<int> vecInt; for(int i = 0; i != MAX_NUM; i++){ vecInt.push_back(i); } vector<int>::iterator iter = vecInt.begin(); cout << "the 1st element: " << *iter << endl; vecInt.push_back(123); cout <<"vecInt's capacity: " << vecInt.capacity() << endl; while(iter != vecInt.end()){ cout << *iter << " "; iter++; } return 0; } /* the 1st element: 0 vecInt's capacity: 16 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -784369068 805499525 0 1 2 3 4 5 6 7 123 */
只修改了MAX_NUM的值,其他一致。再次运行程序时,程序异常。
原因分析
对于vector来说,和数组最大的区别之一就是不需要在初始化的时候声明vector的大小。如果初始化的时候没有指明vector的大小,那么会根据实际的使用情况,在内存中为vector分配的大小分别2->4->8->16...
当MAX_NUM是8时,在for循环进行push_back之后,vecInt在内存中的大小为8。对vecInt再次将123进行push_back的时候,新的vector大小将超过当前的vector大小,所以会自动重新分配存储空间。
由于vector的存储空间已经被重新分配,在push_back123之后iter自然也就指向一个未知的空间,所以程序异常。
为避免vector中在push_back过程中会进行内存的自动重新分配问题,vector提供了reserve函数。
reserve的作用时更改vector的容量,使vector至少可以容纳n个元素。
如果n大于vector当前的容量,reserve会对vector进行扩容,且当push_back的元素数量大于n的时候,会重新分配一个大小为2n的新空间,再将原有的n的元素放入新开辟的内存空间中。其他情况下都不会重新分配vector的存储空间。
Demo:对比使用reserve的区别
说明:在main中声明了两个vector,vecInt为默认初始化,vecIntB使用capacity初始化其容量为100。分别对vetIntA和vecIntB进行同样的操作:
①把0~99依次push_back到vector中,
②在push_back的过程中观察vector的容量capacity是否发生变化。
#include <iostream> #include <vector> #include <stdint.h> using namespace std; void growPushBack(vector<int> &vec, uint16_t size){ for(int i = 0; i < 100; i++){ vec.push_back(i); if(size != vec.capacity()){ size = vec.capacity(); cout << "Capacity changed: " << size << endl; } } } int main(){ uint16_t sz = 0; vector<int> vecIntA; sz = vecIntA.capacity(); //声明vector后未使用reserve,直接进行push_back操作 cout << "Making vecIntA growing:" << endl; growPushBack(vecIntA, sz); cout << "\n========separator========\n" << endl; vector<int> vecIntB; sz = vecIntB.capacity(); //声明vecIntB后用reserve来执行其容量为100 vecIntB.reserve(100); cout << "Making vecIntB growing: " << endl; growPushBack(vecIntB, sz); return 0; } /* Making vecIntA growing: Capacity changed: 1 Capacity changed: 2 Capacity changed: 4 Capacity changed: 8 Capacity changed: 16 Capacity changed: 32 Capacity changed: 64 Capacity changed: 128 ========separator======== Making vecIntB growing: Capacity changed: 100 */
Demo运行结果分析:
如果一个vector使用默认的capacity,那么在push_back操作的时候,会根据添加元素的数量,动态的自动分配空间,2^n递增;如果声明vector的时候,显式的使用capacity(size_type n)来指定vector的容量,那么在push_back的过程中(元素数量不超过n),vector不会自动分配空间。