这篇来学习vector一个互换操作,也就是有两个vector对象,可以通过一个api,把两个对象互换过来。实际上,就是在内存中交换了对象的指针,原来的指针指向新的vector对象。这种交换有时候是很有必要,特别是匿名vector对象进行交换后可以节约内存空间,最后来看看vector的预留空间相关的知识点。

 

1.两个vector互换

互换的函数很简单swap(vect),当前容器和传进来的vect容器进行交换。下面代码先创建两个vector对象,然后进行打印交换前和交换后的容器元素。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    // vector互换
    vector<int> vec;
    // 1 尾部插入元素
    vec.push_back(2);
    vec.push_back(4);
    vec.push_back(6);
    vec.push_back(8);
    vec.push_back(10);

    vector<int> vec2;
    for(int i=10; i>0; i--)
    {
        vec2.push_back(i);
    }

    cout << "before swap:" << endl;
    printVector(vec);
    printVector(vec2);

    cout << "after swap:" << endl;
    vec.swap(vec2);
    printVector(vec);
    printVector(vec2);
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

运行结果:

 

举例容器size变小,容量就没有相应变小

有时候一开始我们创建的vector容器的capacity会很大,然后后面代码通过resize函数,使容器元素个数变小,但是容量还是很大,这样就浪费内存空间,看看下面这个例子。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
    }

    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;

    vec.resize(3);
    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

结果

在28行代码之后,我们可能只需要存储3个元素,但是这个容器的容量还是初始的时候13万多大小,这个内存空间是无法自动回收,很是浪费内存空间。

 

2.匿名vector对象进行互换后节省内存空间

针对上面这种浪费内存空间的场景,我们可以通过匿名对象调用swap方法来解决。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
    }

    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;

    vec.resize(3);
    vector<int>(vec).swap(vec);
    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

就增加第29行代码

第29行代码vector<int>(vec),这个部分是一个匿名对象,根据vec的长度,这里就是3去构造一个新的vector<int>对象,这个对象就是一个匿名对象,然后调用swap函数,把vec容器的容量也减少到3. 这个匿名对象只在29行有效,29行结束的时候会自动会编译器回收内存,这个是匿名对象的特点。

 

3.预留空间

下面看看一个vector容器如果要插入10万个数,在g++编译环境下需要动态扩展容器容量多少次才能解决存储10万个数元素

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    int num = 0; // 统计内存开辟次数
    int *p = NULL;  
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
        if(p != &vec[0])
        {
            p = &vec[0];
            num++;
        }
    }

    cout << "num:" << num << endl;
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

上面这个指针p,一开始是NULL, 我们知道在内存中,数组或者字符串的指针都是默认指向数组第一个元素的位置。这个p就是通过这个特点来统计,只要扩容一次,数组首地址就发生变化一次,这样统计扩容次数的。

我这里是18次出现扩容,如果在vs上可能是30次左右。也就是发生18次动态扩容才搞定这个容器存储10万个数。如果我们一开始就大概知道这个容器需要多少空间,我们可以通过预留空间的办法去减少容器动态扩容的次数。

在vector容器中,预留空间使用reserve(int n)。

reserve(int len);  //容器预留len个元素长度,预留位置不初始化,元素不可以访问

这个预留空间的作用是减少vector在动态扩展容量时的扩展次数,看下面代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    vec.reserve(100000);
    int num = 0; // 统计内存开辟次数
    int *p = NULL;  
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
        if(p != &vec[0])
        {
            p = &vec[0];
            num++;
        }
    }

    cout << "num:" << num << endl;
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

这样一次就搞定,节约动态扩容的时间。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐