C++ vector深究

一  size和capacity区别

size的大小是指的容器所含的元素个数。STL容器都含有该方法,取得容器的元素个数。

capacity的大小是指容器所分配的内存大小。vector特有的方法。(因为别的容器大小和容量相等,所以没必要提供capacity)

关系:capacity >= size

二 resize和reserve

(1)resize 重新分配元素多少  --> 改变size大小也可以改变capacity大小

       resize可以减少容器的容量

(2)reserve 预留一定的空间(分配容器内存,必须是大于等于原来的内存空间,不然无效) -->改变capacity大小

      1.如果预留空间大于当前容量(),则分配新的存储空间,否则该方法不起作用。

   2.reserve()不能用于减少容器的容量,为此提供了shrink_to_fit() 

假设

vector<int> sample;

当前size()为50, capacity()为100,经过以下操作:

(1) resize(10).  //size() == 10; 10到49下标的元素被删除. capacity()==100,不变,没有进行内存重新分配.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.resize(10);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:10

capacity:100


(2) resize(60).  //size() == 60; 50到59下标用默认构造函数填充. capacity() == 100,不变,没有进行内存重新分配.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.resize(60);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:60

capacity:100

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 


(3) resize(60, 9999).  //size() == 60; 50到59下标用9999填充. capacity() == 100,不变,没有进行内存重新分配.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.resize(60,999);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    for(int i = 0;i < v.capacity();i++)
        cout << v[i] << " ";
    cout << endl;

size:50

capacity:100

size:60

capacity:100

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 999 999 999 999 999 999 999 999 999 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 


(4) resize(200). //size() == 200; 50到199下载用默认构造函数填充. capacity() == 200, 自动扩容,重新分配内存.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.resize(200);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:200

capacity:200


 (5) reserve(10). //size() == 50; 不变,没有元素被删除, capacity() == 100, 不变. 即reserve调用没起作用.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.reserve(10);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:50

capacity:100


(6) reserve(60). //size() == 50; 元素没有变, capacity() == 100, 不变. 即reserve调用没起作用.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.reserve(60);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:50

capacity:100


(7) reserve(200). //size() == 50; 元素没有变, capacity() == 200, 扩容,重新分配内存.

    vector<int> v(50);
    v.reserve(100);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.reserve(200);
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;

size:50

capacity:100

size:50

capacity:200


三 push_back()  insert()原理

      push_back在容器的尾部增加元素,这里的尾部是指最后一个元素的后面(这个很重要,区别size和capacity的关键)vector在push_back的时候,如果空间不足,会自动增补一些空间,如果没有预留的空间可用,就直接申请另一块可用的连续的空间,把数据拷贝过去,然后删除旧空间,使用新空间,结果造成效率低下。

  insert在指定位置处的元素前插入一个新的元素。直接使容器的大小(Size)增加,增加的值就是所插入元素的个数。当且仅当新的容器的大小超过当前容器的容量(Capacity),才会导致一次已分配的存储空间的自动重分配。因为向量用数组作为它的内部存储结构,将元素插入除了末尾的其它位置会导致容器迁移该位置后的所有元素到新的位置。相比其它类型的顺序容器(如 std::list 或 std::forward_list C++11),该操作是极其耗性能的,这样子看来,insert比push_back效率低

     push_back和insert当前空间不足的情况下,会自动增补一些空间,如果没有预留的空间可用,就直接申请另一块可用的连续的空间,把数据拷贝过去,然后删除旧空间,使用新空间,其新的空间大小是旧的2倍(不同编译器倍数不一样)

  如果在事先预见到有较大空间需求,就可以先用reserve预留一定的空间,避免内存重复分配和大量的数据搬移,提高了效率 。

void fun3()
{
    vector<int> myVec(3);
    cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    myVec.push_back(1);
    cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
}

运行结果:

size:3 capacity:3

size:4 capacity:6

测试vector每次增长分配的内存是几倍  --> 当超过当前容器的容量,将以2的倍数增长(本环境mac g++编译器,不同环境和编译器结果不同)


四  容器初始化

(1)vector<int> v(10);

定义一个容器v,容器的size = 10,capacity = 10

(2)vector<int> v;

       v.reserve(10);

定义一个容器v,容器的size = 0,capacity = 10  ==> 该容器容器内存大小10,但是目前容纳的元素个数为0,可以通过push_back来增加元素。

    vector<int> e;
    e.reserve(10);
    cout << "size:" << e.size() << endl;
    cout << "capacity:" << e.capacity() << endl;
    for(int i = 0; i < 10; i++)
    {
        e.push_back(i);
        cout << e[i] << " "; //输出正常0-9
    }
    cout << endl;
    cout << "size:" << e.size() << endl;
    cout << "capacity:" << e.capacity() << endl;

运行结果:

size:0

capacity:10

0 1 2 3 4 5 6 7 8 9 

size:10

capacity:10

由结果可以看出,因为容器e没有元素,所以push_back是从第一个开始增加。


(3)

    vector<int> v(10);  

    v.reserve(20); 

定义了一个容器v,容器的size = 10,capacity = 20 ==> 该容器容器内存大小20,但是目前容纳的元素个数为10,可以通过push_back来增加元素。

    vector<int> c(10);
    c.reserve(20);
    cout << "size:" << c.size() << endl;
    cout << "capacity:" << c.capacity() << endl;
    for(int i = 0; i < 10; i++)
    {
        c.push_back(i);
    }
    for(int i = 0; i < c.size(); i++)
    {
        cout << c[i] << " ";
    }
    cout << endl;
    cout << "size:" << c.size() << endl;
    cout << "capacity:" << c.capacity() << endl;

运行结果:

size:10

capacity:20

0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 

size:20

capacity:20

由结果可以看出,因为容器c含有10个元素,所以push_back是从第11个开始增加。

(4)

void fun5()
{
    vector<int> c(10);  //这个10代表容器的元素个数大小
    c.reserve(20);      //这个20代表容器的容量大小 所以后面push_back是从
    cout << "size:" << c.size() << endl;
    cout << "capacity:" << c.capacity() << endl;

    c[5] = 5;
    
    c[10] = 10;
    c[15] = 15;
    
    c[20] = 20;
    for(int i = 0;i < c.capacity();i++)
        cout << c[i] << " ";
    cout << endl;
    
    c.push_back(1);
    c.push_back(1);
    c.push_back(1);
    c.push_back(1);
    c.push_back(1);
    c.push_back(1);
    c.push_back(1);
    for(int i = 0;i < c.capacity();i++)
        cout << c[i] << " ";
    cout << endl;
}

运行结果:

size:10

capacity:20

0 0 0 0 0 5 0 0 0 0 10 0 0 0 0 15 0 0 0 0 

0 0 0 0 0 5 0 0 0 0 1 1 1 1 1 1 1 0 0 0 


 我们都知道, vector是在内存中是连续分布的,所以设计上总会在所有已经有元素外预留一些空间,否则每次追加新元素时都要再次分配内存,那准备就绪将很低.

假如当vector中可能会存在约10个元素时, 比较两种做法:

1. vector<int> myVec, 然后10次调用 myVec.push_back(****)

2. vector<int> myVec(10), 然后10次调用 myVec.push_back(****)

void fun1()
{
    vector<int> myVec;
    cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    for(int i = 0;i < 10;i++){
        myVec.push_back(i);
        cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    }
}

void fun2()
{
    vector<int> myVec(10);
    cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    for(int i = 0;i < 10;i++){
        myVec.push_back(i);
        cout << "size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    }
}
int main()
{
    fun1();
    cout << endl;
    fun2();
}

运行结果:

size:0 capacity:0

size:1 capacity:1     1次

size:2 capacity:2     2次

size:3 capacity:4     3次

size:4 capacity:4

size:5 capacity:8     4次

size:6 capacity:8

size:7 capacity:8

size:8 capacity:8

size:9 capacity:16    5次

size:10 capacity:16


size:10 capacity:10  1次

size:11 capacity:20  2次

size:12 capacity:20

size:13 capacity:20

size:14 capacity:20

size:15 capacity:20

size:16 capacity:20

size:17 capacity:20

size:18 capacity:20

size:19 capacity:20

size:20 capacity:20

由结果看:做法2只需要进行2次内存分配,而做法1进行5次内存分配了.

可以使用下面的方法:

void fun3()
{
    vector<int> myVec;
    vector<int> yourVec;
    yourVec.reserve(10);
    cout << "size:" << yourVec.size() << " capacity:" << yourVec.capacity() << endl;
    for(int i = 0;i < 10;i++){
        yourVec.push_back(i);
        cout << "size:" << yourVec.size() << " capacity:" << yourVec.capacity() << endl;
    }
    cout << endl <<"size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    myVec = yourVec;
    cout  <<"size:" << myVec.size() << " capacity:" << myVec.capacity() << endl;
    for(int i = 0;i < 10;i++)
        cout << myVec[i] << " ";
    cout << endl;
}

size:0 capacity:10

size:1 capacity:10

size:2 capacity:10

size:3 capacity:10

size:4 capacity:10

size:5 capacity:10

size:6 capacity:10

size:7 capacity:10

size:8 capacity:10

size:9 capacity:10

size:10 capacity:10


size:0 capacity:0

size:10 capacity:10  1次

0 1 2 3 4 5 6 7 8 9 

由上面可知,内存只扩容了一次。

六 二维容器

#include <iostream>
#include <vector>

using namespace std;

static vector<vector<int> > v(5);

void fun1(int n)
{
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    for(int i = 0;i < v.size();i++){
        v[i].reserve(100);
        cout << "size:" << v[i].size() << endl;
        cout << "capacity:" << v[i].capacity() << endl;
    }
    cout << "************1***********" << endl;

    //清除 二维容器的第二维
    for(int i = 0;i < v.size();i++){
        v[i].clear();
        cout << "size:" << v[i].size() << endl;
        cout << "capacity:" << v[i].capacity() << endl;
    }
    //清除 二维容器的第一维
    //v.clear();

    
    cout << "************2***********" << endl;
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    
    for(int i = 0;i < v.size();i++){
        for(int j = 0;j < v[i].capacity();j++){
            v[i].push_back(n);
        }
    }
    cout << "************3***********" << endl;
    for(int i = 0;i < v.size();i++){
        cout << "size:" << v[i].size() << endl;
        cout << "capacity:" << v[i].capacity() << endl;
    }
    cout << "************4***********" << endl;
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    for(int i = 0;i < v.size();i++){
        for(int j = 0;j < v[i].capacity();j++){
            cout << v[i][j] << " ";
        }
        cout << endl;
    }

}

int main()
{
    fun1(1);
}

猜你喜欢

转载自blog.csdn.net/qq_31930499/article/details/79801247