vector 几乎是 C++ 选手接触最早、出场率最高的容器,但很多人只会当“能自动扩容的数组”用。想写题稳、面试不虚、手撕源码有东西可写,就必须既会用标准库里的 std::vector,又能看懂它底层那三根指针在干什么。这篇文章用一套完整示例和手撕代码,把 vector 从上到下拆给你看,让它真正变成你的基础武器。

目录

1. vector的介绍及使用

1.1 vector是什么

1.2 vector的使用

1.2.1 vector的定义与构造

1.2.2 vector迭代器的使用

1.2.3 vector的容量与空间增长

1.2.4 vector的增删查改

1.2.5 vector迭代器失效问题

1.2.6 vector在OJ中的使用

2. vector深度剖析及模拟实现

2.1 std::vector的核心框架

2.2 使用memcpy拷贝问题

2.3 动态二维数组理解

3.手撕vector完整代码


1. vector的介绍及使用

1.1 vector是什么

简单描述:

vector就是“会自动扩容的顺序表”,底层是一块连续的动态数组。

关键特性:

  • 元素在内存中连续存放,可以像普通数组一样O(1)随机访问;

  • 支持尾插、尾删、任意位置插入、删除等操作;

  • 内部自动帮你管理动态内存,不用自己new[]/delete[]

学习STL可以想成三个阶段:

  1. 能用:知道有哪些接口,能查文档、能写代码;

  2. 明理:大致理解每个接口做了什么、复杂度如何、可能有哪些坑;

  3. 能扩展:能自己模拟实现一个差不多的容器,或者读得懂源码。


1.2 vector的使用

vector一定要学会查文档:构造函数有哪些、迭代器有哪些、容量相关有哪些、增删查改有哪些。这里把最常用的挑出来,按“构造→迭代器→容量→增删查改→迭代器失效→OJ实践”的顺序来。


1.2.1 vector的定义与构造

常见构造形式可以对应到下面这个表:

构造形式 说明
vector()(重点) 无参构造,生成空vector
vector(size_type n,const value_type& val=value_type()) 构造并初始化n个值为val的元素
vector(const vector& x)(重点) 拷贝构造
vector(InputIterator first,InputIterator last) 区间构造,用[first,last)初始化

代码示例:

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

void TestVectorConstruct()
{
    vector<int> v1;                 //空vector

    vector<int> v2(5);              //5个int,默认值0
    vector<int> v3(5, 2);           //5个int,每个都是2

    int a[] = { 1,2,3,4 };
    vector<int> v4(a, a + 4);       //区间构造

    vector<int> v5(v4);             //拷贝构造

    for (size_t i = 0; i < v5.size(); ++i)
    {
        cout << v5[i] << " ";
    }
    cout << endl;
}

1.2.2 vector迭代器的使用

迭代器可以理解成“包装过的指针”。对vector来说,迭代器本质就是T*,所以行为基本就是指针行为。

常见接口:

接口 说明
begin() 返回指向第一个元素的iterator/const_iterator
end() 返回指向“最后一个元素的下一个位置”的iterator/const_iterator
rbegin() 返回指向最后一个元素的reverse_iterator
rend() 返回指向“第一个元素前一个位置”的reverse_iterator

示例:

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

void TestVectorIterator()
{
    vector<int> v{ 1,2,3,4,5 };

    //正向迭代器
    for (auto it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;

    //反向迭代器
    for (auto rit = v.rbegin(); rit != v.rend(); ++rit)
    {
        cout << *rit << " ";
    }
    cout << endl;

    //范围for(底层也是begin+end)
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}

1.2.3 vector的容量与空间增长

关键知识点:size 和 capacity

  • size():当前“有效元素”的个数;

  • capacity():当前底层数组能容纳的最大元素个数。

常用容量相关接口:

容量空间 接口说明
size() 当前元素个数
capacity() 当前容量
empty() 是否为空
resize()(重点) 改size,必要时扩容并初始化新元素
reserve()(重点) 改capacity,不改size

重点区别:

  • resize(n)会把size改成n,如果变大了,新位置要么填默认值,要么填你传进来的值;

  • reserve(n)只保证capacity至少为n,不改变size,等于提前打地基。

扩容策略对比

代码示例:

void TestVectorExpand()
{
    size_t sz;
    vector<int> v;
    sz = v.capacity();
    cout << "making v grow:" << '\n';
    for (int i = 0; i < 100; ++i)
    {
        v.push_back(i);
        if (sz != v.capacity())
        {
            sz = v.capacity();
            cout << "capacity changed:" << sz << '\n';
        }
    }
}

在不同编译器下运行,会发现:

  • VS下capacity大致按1.5倍扩;

  • g++下capacity大致按2倍扩。

想要减少扩容带来的拷贝开销,可以搭配reserve使用:

//提前reserve,避免频繁扩容
void TestVectorExpandOP()
{
    vector<int> v;
    size_t sz = v.capacity();

    v.reserve(100);    //提前把容量拉满
    cout<<"making v grow:"<<'\n';
    for(int i = 0; i < 100; ++i)
    {
        v.push_back(i);
        if(sz != v.capacity())
        {
            sz = v.capacity();
            cout<<"capacity changed:"<<sz<<'\n';
        }
    }
}

1.2.4 vector的增删查改

这里把最常用的接口整理成表:

接口名 说明
push_back(重点) 尾插一个元素
pop_back(重点) 尾删一个元素
insert 在迭代器position前插入元素
erase 删除position位置元素
swap 交换两个vector的内部空间
operator[](重点) 像数组一样通过下标访问
find 在线性区间中查找元素(算法库里的普通函数)

代码示例:

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

void TestVectorCRUD()
{
    vector<int> v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    v.insert(v.begin(), 0);    //在最前面插入0

    auto pos = find(v.begin(), v.end(), 2);
    if(pos != v.end())
    {
        v.erase(pos);     //删除2
    }

    v.pop_back();    //删除最后一个元素

    for(size_t i = 0; i < v.size(); ++i)
    {
        cout<<v[i]<<" ";
    }
    cout<<endl;
}

1.2.5 vector迭代器失效问题

迭代器底层就是指针,只要这块指针指向的空间“失效”了,迭代器就失效了。失效之后继续用它去解引用、++、--,都是未定义行为,要么崩,要么给你一些诡异的数据。

对于vector,典型会“搞坏”迭代器的操作有两类:

  1. 可能引起底层空间变化的操作:

    • resize

    • reserve

    • insert

    • assign

    • push_back

  2. 删除指定位置元素的erase

例子:

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

int main()
{
    vector<int> v{ 1,2,3,4,5,6 };
    auto it = v.begin();

    //将有效元素个数增加到100,多出的用8填充,过程中会扩容
    //v.resize(100, 8);

    //reserve只改变容量,操作期间也可能导致底层空间改变
    //v.reserve(100);

    //在前面插入元素,也可能导致扩容
    //v.insert(v.begin(), 0);

    //尾插也有可能触发扩容
    //v.push_back(8);


    /*
    上面这些操作只要触发了扩容,底层旧空间就会被释放。
    但it还指向旧空间,后面while里继续用it遍历,相当于在操作一块已经被free掉的内存,
    结果要么崩溃,要么打印出完全莫名其妙的数据。
    */

    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    return 0;
}

正确用法:只要做了可能改变空间的操作,如果还想使用迭代器,先给它重新赋值:

it = v.begin();

erase例子:

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

int main()
{
    int a[] = { 1,2,3,4 };
    vector<int> v(a, a + sizeof(a) / sizeof(int));

    auto pos = find(v.begin(), v.end(), 3);
    v.erase(pos);   //删除3

    cout << *pos << endl;    //行为未定义
    return 0;
}

逻辑上看,erase只是在原地搬移后面的元素,没有扩容,也没换空间,似乎pos还能继续用。
但标准规定:被删除位置的迭代器就是失效的,不要再用。

最容易错误的地方,是“边遍历边删除”:

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

int main()
{
    vector<int> v{ 1,2,3,4 };
    auto it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 0)
            v.erase(it);
        ++it;
    }
    return 0;
}

这段代码想删掉所有偶数,结局是要么跳着删,要么崩掉。

正确写法是:用erase的返回值接住新的位置:

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

int main()
{
    vector<int> v{ 1,2,3,4 };
    auto it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 0)
        {
            //继续从删除位置的“下一个”元素开始
            it = v.erase(it);     
        }
        else
        {
            ++it;
        }
    }
    for (auto e : v)
        cout << e << " ";
    cout << endl;
    return 0;
}

再看一下Linux下g++的:

//扩容后继续用旧迭代器
int main()
{
    vector<int> v{ 1,2,3,4,5 };
    for (size_t i = 0; i < v.size(); ++i)
        cout << v[i] << " ";
    cout << endl;

    auto it = v.begin();
    cout << "扩容之前,vector的容量为:" << v.capacity() << endl;

    //通过reserve强制扩容
    v.reserve(100);
    cout << "扩容之后,vector的容量为:" << v.capacity() << endl;

    //此时it一定失效了,但在g++下不一定当场崩溃,而是打印各种诡异数据
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    return 0;
}

在g++下输出:

1 2 3 4 5
扩容之前,vector的容量为:5
扩容之后,vector的容量为:100
0 2 3 4 5 409 1 2 3 4 5

程序没崩,但结果显然不对。

同样的问题出现在erase上:

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

int main()
{
    vector<int> v{ 1,2,3,4,5 };
    auto it = find(v.begin(), v.end(), 3);
    v.erase(it);    //删除中间的3

    cout << *it << endl;   //g++下会输出4
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    return 0;
}

这段在g++下看起来没问题,但标准意义上这就是在用失效迭代器,只能说运气好没崩。

结论

只要涉及可能改变vector结构的操作(扩容、插入、删除等),用之前先判断迭代器是不是需要重置;erase要用返回值接收新位置。


string同理,在插入、扩容、erase之后,迭代器照样会失效:

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

void TestStringIterator()
{
    string s("hello");
    auto it = s.begin();

    //resize会触发扩容,旧迭代器it直接失效
    //s.resize(20,'!');

    while (it != s.end())
    {
        cout << *it;
        ++it;
    }
    cout << endl;

    it = s.begin();
    while (it != s.end())
    {
        cout << *it;
        ++it;
    }
    cout << endl;
}

1.2.6 vector在OJ中的使用

题一:只出现一次的数字 I

题目大意:一个整数数组中,除了一个数字只出现一次外,其余每个数字都出现两次,找出这个只出现一次的数字。

套路:异或。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int value = 0;
        for (auto e : nums)
        {
            value ^= e;
        }
        return value;
    }
};

题二:杨辉三角

题目大意:给定一个行数numRows,生成杨辉三角的前numRows行。

核心思想:

  • 每行头尾都是1;

  • 中间的第j个数是上一行jj-1之和。

//核心思想:每一行先resize到合适长度,头尾设为1,中间用上一行相邻两数之和
class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv(numRows);

        for (int i = 0; i < numRows; ++i)
        {
            vv[i].resize(i + 1, 1);
        }

        for (int i = 2; i < numRows; ++i)
        {
            for (int j = 1; j < i; ++j)
            {
                vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
            }
        }

        return vv;
    }
};

通过这些练习可以发现:

  • vector最常用的就是“构造+遍历+插入/删除”;

  • 遍历时多数情况下大家更喜欢用operator[]或范围for

  • 删除时要特别注意迭代器失效问题。

后面可以继续用vector完成这些题作为练习:

  1. 删除排序数组中的重复项

  2. 只出现一次的数II

  3. 只出现一次的数III

  4. 数组中出现次数超过一半的数字

  5. 电话号码字母组合


2. vector深度剖析及模拟实现

2.1 std::vector的核心框架

可以把vector的内部想象成管理三根指针的类:

  • _start:指向首元素;

  • _finish:指向“最后一个元素的下一个位置”;

  • _end_of_storage:指向“整块空间的尾后位置”。

结构:

namespace my
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        vector()
            :_start(nullptr)
            , _finish(nullptr)
            , _end_of_storage(nullptr)
        {}

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            return _end_of_storage - _start;
        }

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        T& operator[](size_t i)
        {
            return _start[i];
        }

        const T& operator[](size_t i) const
        {
            return _start[i];
        }

        //push_back/resize/reserve/insert/erase等操作
        //本质都是在这三根指针基础上移动和重分配

    private:
        iterator _start;
        iterator _finish;
        iterator _end_of_storage;
    };
}

执行:

my::vector<int> v(2,9);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

比如:

  1. 一开始size=2,capacity=2,里面两个9;

  2. 最多只多塞一个1时会扩容,重新new一块更大的空间;

  3. 把老数据搬过去,更新_start/_finish/_end_of_storage,旧空间释放;

  4. 之后继续push_back,直到再次触发扩容。


2.2 使用memcpy拷贝问题

现在假设你在自己的bit::vector里实现reserve时图省事,直接用了memcpy

int main()
{
    my::vector<my::string> v;
    v.push_back("1111");
    v.push_back("2222");
    v.push_back("3333");
    return 0;
}

这里的my::string可以理解成类似在string那一篇博客中模拟实现的自定义String类:内部有char* _str,构造时new[]一块空间,析构时delete[]

关于memcpy

  1. 它做的是内存的二进制拷贝,哪怕是结构体/对象,也只是把字节照抄一份;

  2. 拷贝“纯值类型”时(比如int/double)没问题,拷贝“带资源”的类型(比如内部有指针、句柄)时,就是浅拷贝

过程:

  1. 插入"1111"后,v[0]里的_str指向一块堆上的"1111";

  2. 插入"2222"时触发扩容,reserve里:

    • new出一块更大的raw内存;

    • memcpy把老数组里的三个bite::string对象“按字节复制”到新数组;

    • 释放老数组整块内存;

  3. 结果:

    • 新数组里的三个my::string对象,它们的_str指针仍然指向老数组里那块已经被释放的"1111"/"2222"/"3333"空间;

    • 老数组这一块空间已经被delete[]掉了;

    • 稍后新数组里的my::string析构时,又会再delete[] _str一次,出现二次析构。


1)插入"1111"后,v[0]的_str指向0x0012ffa0
2)插入"2222"扩容,新空间里有两个空string,对它们memcpy拷贝后,_str都指向旧地址0x0012ffa0
3)释放旧空间后,这些指针全都变成野指针,后面二次析构就会崩。

结论

只要对象里“涉及资源管理”,就千万不能用memcpy做对象之间的拷贝。memcpy只是浅拷贝,很容易导致内存泄漏、重复释放甚至程序直接崩溃。

正确思路是:

  • 对于有资源管理的对象,要逐个调用拷贝构造函数

void reserve(const size_t n)
{
	if (n > capacity())
	{
		size_t old_size = size();
		T* tmp = new T[n];
		// 若是需要深拷贝类型(自定义类型)如vector<string>/vector<vector<int>>,memcpy就会失败
		// memcpy只把_start内存的字节拷贝到tmp,不会调用拷贝构造
		// 新旧两个对象的指针会指向同一块堆内存,析构时二次释放 就报错
		//memcpy(tmp, _start, sizeof(T) * old_size);

		for (size_t i = 0; i < old_size; ++i)
		{
			tmp[i] = _start[i];
		}
		delete[] _start;

		_start = tmp;
		_finish = tmp + old_size;
		_end_of_storage = tmp + n;
	}
}

2.3 动态二维数组理解

vector构建“动态二维数组”,以杨辉三角为例。

//以杨辉三角的前n行为例:假设n为5
void test2vector(size_t n)
{
    //使用vector定义二维数组vv,vv中的每个元素都是vector<int>
    my::vector<my::vector<int>> vv(n);

    //将二维数组每一行中的vector<int>中的元素全部设置为1
    for (size_t i = 0; i < n; ++i)
        vv[i].resize(i + 1, 1);

    //给杨辉三角第一列和对角线之外的元素赋值
    for (int i = 2; i < (int)n; ++i)
    {
        for (int j = 1; j < i; ++j)
        {
            vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
        }
    }
}

如果n = 5vv的结构可以想象成:

  1. vv本身是一个my::vector<my::vector<int>>,内部有5个元素;

  2. 每个vv[i]都是一个my::vector<int>对象,初始时里面还没有任何元素;

  3. 调用resize之后,每行的_start/_finish/_end_of_storage都指向自己那一行的数据。


左边是vv本体,右边是vv[0]~vv[4],每个都是一个vector对象

填充完后每一行分别是:
vv[0]:1
vv[1]:1 1
vv[2]:1 2 1
vv[3]:1 3 3 1
vv[4]:1 4 6 4 1

使用标准库std::vector<std::vector<int>>去做动态二维数组,实际底层布局和上面这张图是一致的:

  • 外层vector是一维数组,存的是每一行的vector对象;

  • 每一行又是一个独立的动态数组,长度可以不一样,非常适合存放像杨辉三角这种每行长度不同的结构。

这种嵌套写法,既保留了a[i][j]这种二维访问方式,又能享受自动扩容带来的内存安全。


3.手撕vector完整代码

vector.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<algorithm>
#include<vector>
#include<assert.h>
using namespace std;
namespace my {
	template<class T>
	class vector {
	public:

		//迭代器
		typedef T* iterator;
		typedef const T* const_iterator;

		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}

		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (int i = 0; i < n; ++i)
				push_back(val);
		}

		//在vector<int> v(10,1) 的形式中,不这样写参数将被识别成两个迭代器,执行InputIterator类构造
		vector(int n, const T& val = T())
		{
			reserve(n);
			for (int i = 0; i < n; ++i)
				push_back(val);
		}

		// 默认构造	不写默认构造,因为类中有拷贝构造,
		// 编译器认为也有构造函数,将不会默认生成默认构造,会报错
		/*vector()
		{}*/

		//C++11 强制生成默认构造
		vector() = default;

		//拷贝构造	
		vector(const vector<T>& v)
		{
			reserve(v.size());
			for (auto& e : v)
			{
				push_back(e);
			}
		}

		//析构函数
		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}

		void clear()
		{
			_finish = _start;
		}
		//传统写法
		//vector<int> operator=(const vector<T>& v)
		//{
		//	if (this != &v)
		//	{
		//		clear();
		//		reserve(v.size());
		//		for (auto& e : v)
		//		{
		//			push_back(e);
		//		}
		//	}
		//	return *this;
		//}

		//现代写法
		void swap(vector<T> v)
		{
			std::swap(_start, v._star);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}
		vector<int> operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _end_of_storage - _start;
		}
		bool empty()
		{
			return _start == _finish;
		}
		void reserve(const size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();
				T* tmp = new T[n];
				// 若是需要深拷贝类型(自定义类型)如vector<string>/vector<vector<int>>,memcpy就会失败
				// memcpy只把_start内存的字节拷贝到tmp,不会调用拷贝构造
				// 新旧两个对象的指针会指向同一块堆内存,析构时二次释放 就报错
				//memcpy(tmp, _start, sizeof(T) * old_size);

				for (size_t i = 0; i < old_size; ++i)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;

				_start = tmp;
				_finish = tmp + old_size;
				_end_of_storage = tmp + n;
			}
		}

		void resize(const size_t n, const T& val = T())
		{
			if (_finish > _start + n)
				_finish = _start + n;
			else
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}
		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			*_finish = x;
			++_finish;
		}
		T& operator[](size_t n)
		{
			assert(n < size());
			return _start[n];
		}
		const T& operator[](size_t n) const
		{
			assert(n < size());
			return _start[n];
		}

		void pop_back()
		{
			assert(!empty());
			--_finish;
		}

		iterator insert(iterator pos, const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				pos = _start + len;
			}
			iterator end = _finish;
			while (end > pos)
			{
				*end = *(end - 1);
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			iterator it = pos + 1;
			while (it != end())
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
			return pos;
		}

	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};
	template<class T>
	void print_vector(const vector<T>& v)
	{
		//规定:没有实例化的类模板中取东西,编译器不能判断const_iterator
		//是类型还是静态成员变量
		//typename vector<T>::const_iterator it = v.begin();
		auto it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		//for (auto& x : v)
		//	cout << x << " ";
		//cout << endl;
	}

	//通用模版
	template<class Container>
	void print_container(const Container& v)
	{
		auto it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		//for (auto& x : v)
		//	cout << x << " ";
		//cout << endl;
	}

	void test01()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(4);
		v.push_back(5);
		//for (int i = 0; i < v.size(); ++i)
		//	cout << v[i] << " ";
		//cout << endl;
		print_vector(v);

		v.insert(v.begin() + 3, 99);
		print_vector(v);
		int x; cin >> x;
		//typename vector<int>::iterator p = find(v.begin(), v.end(), x);
		auto p = find(v.begin(), v.end(), x);

		if (p != v.end())
		{
			//insert以后p就失效,不要直接访问,要访问就需要更新这个失效的迭代器的值
			/*v.insert(p, 40);
			(*p) *= 10;*/

			p = v.insert(p, 40);
			*(p + 1) *= 10;
		}
	}
	void test02()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(4);

		//2v.push_back(5);

		print_vector(v);

		//typename vector<int>::iterator it = v.begin();
		auto it = v.begin();

		while (it != v.end())
		{
			if (*it % 2 == 0)
				//v.erase(it);
				it = v.erase(it);
			else
				++it;
		}
		print_vector(v);
	}
	void test03()
	{
		vector<int> v;
		v.resize(5, 1);
		print_vector(v);

	}

	void test04()
	{
		vector<string> v1(10, "1111111111");
		print_container(v1);

		vector<int> v2(10);
		print_container(v2);

		//需要参数更匹配的拷贝构造,如第一个参数为int n
		vector<int> v3(10, 1);
		print_container(v3);

	}

	void test05()
	{
		vector<string> v;
		v.push_back("1111111111111");
		v.push_back("1111111111111");
		v.push_back("1111111111111");
		v.push_back("1111111111111");
		print_container(v);		//没扩容

		v.push_back("1111111111111");
		print_container(v);		//扩容,检查扩容不能使用memcpy
	}

}

test.cpp:

#include"vector.h"

int main()
{
	//my::test01();
	//my::test02();
	//my::test03();
	//my::test04();
	my::test05();
	return 0;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐