目录

一、vector简介

二、常用接口说明

1、vector类对象的常用构造

2、vector对象容量操作

3、vector类对象的访问及遍历操作                                                          

4、vector 增删查改

三、vector容器深度剖析及模拟实现

3.1、类对象的初始化

1、默认构造

2、拷贝构造(⭐)

3、迭代器区间构造(⭐)

4、用n个val初始化

5、赋值重载——operator=(⭐)

4、析构函数

3.2、测试接口(用于打印数据)——print_Container

3.3、功能函数接口

1、迭代器(⭐)

2、获取有效数据个数——_size

3、获取数组空间大小——_capacity

4、判空——empty

5、访问操作符重载——operator[ ](⭐)

6、清理空间——clear

7、清除迭代器指向位置的数据——erase(⭐)

8、申请空间——reserve(⭐)

9、扩容——resize(⭐)

10、尾插——push_back(⭐)

11、尾删——pop_back

12、指定位置插入——insert(⭐)

四、完整源码


一、vector简介

std::vector:是 C++ 标准库中的一个容器,也是STL最常用容器之一,定义在<vector>头文件中,它本质是一个动态数组,具有数组随机访问的特性,同时又能在运行时动态调整大小,自动管理内存,在 C++ 开发中应用广泛。

基本特性:

  • 动态调整大小:无需在创建时指定固定长度,可根据需要添加或删除元素,在元素数量超过当前容量时自动扩容。
  • 连续内存存储vector中的元素在内存中是连续存储的,这使得它支持像普通数组一样通过下标快速访问元素。
  • 自动内存管理:内部实现了对内存的自动分配和释放,无需手动调用newdelete,减少了内存泄漏的风险。

std::vector的文档(方便大家随时查阅):(⭐)

https://legacy.cplusplus.com/reference/vector/vector/?kw=vector

二、常用接口说明

1、vector类对象的常用构造

实现vector对象在定义的同时初始化

            构造函数(construct)(⭐)                                           功能
vector() 默认构造
vector(size_t n, const value_type& val = value_type()) 构造一个对象并初始化为为n个val,如果不传第二个参数,初始化为value_type()的默认值
vector(const value_type& v) 拷贝构造,用v对象来初始化
vector(InputIterator first,InputIterator end) 使用迭代器区间来初始化
#include<iostream>
using namespace std;
#include<vector> //头文件

void test1()
{
    vector<int> v1;
	vector<int> v2(5,1); // 使用5个1来初始化int类型的对象v2
    vector<int> v3(v1); // 使用v2对象来初始化v3对象
	vector<int> v4(v1.begin(), v1.end()); // 用迭代器区间初始化v4对象
}

2、vector对象容量操作

      函数接口                                              功能
  ⭐   size() 获取有效数据个数
  ⭐ capacity() 获取空间大小
     empty() 判断是否为空
     
⭐resize (size_type n, value_type val = value_type())
扩容并完成初始化
   
⭐reserve (size_type n)
申请n个空间
void test2()
{
	vector<int> v1(5, 1);
	cout << v1.size() << endl;  // 获取v1对象的有效数据个数
	cout << v1.capacity() << endl; // 获取v1对象的空间大小
}

可以通过下面一段代码来感受reserve扩容的过程:

void test3()
{
	vector<int> v2;
	v2.push_back(0);
	size_t sz = v2.capacity();
	cout << "capacity:" << sz << endl;
	int i = 0;
	while (i < 100)
	{
		v2.push_back(i);
		if (sz != v2.capacity()) // 当原来空间大小变化即扩容时,打印新的空间大小
		{
			sz = v2.capacity();
			cout << "reserve:" << sz << endl;
		}
		i++;
	}
}

// resize
void test4() 
{
	vector<int> v3(10, 1);
	v3.resize(15, 2);
	v3.resize(10, 0); // resize()不会让v3缩容,但是会改变有效数据个数
	cout << v3.capacity() << endl;
}

注意:std::vector 的 reserve(n) 函数只是预留内存空间,并不会真正构造元素,也不会改变 vector 的大小(size())。 此时 vector 中没有任何有效元素,size() 仍为 0。而代码中使用 v[i]去访问和修改下标为 0 到 4 的元素,相当于访问了 “不存在的内存区域”,属于越界访问。

// 错误示范
void test6()
{
	vector<int> v;
	v.reserve(5);
	for (int i = 0; i < 5; i++)
	{
		v[i] = i + 1;
	}
}

3、vector类对象的访问及遍历操作                                                          

                      函数                                            功能
⭐operator[ ] 重载运算符[],通过访问数组元素的方式返回pos位置的元素
⭐v.begin()  begin获取一个字符的迭代器(地址),用于从前往后遍历数组。
⭐v.end() end获取最后一个元素下一个位置的迭代器(地址)
v.rbegin() rbegin()返回的是反向迭代器,指向数组的最后一个元素,用于从后往前遍历数组。
v.rend() end获取第一个元素前一个位置的迭代器(地址)
⭐范围for C++11支持更简洁的范围for的新遍历方式,与auto关键字联用

vector对象的遍历与string对象的遍历方式相同,前面string类中已经做了详细的说明,这里简单地

说明:

void test5()
{
	vector<int> v1(5, 1);
	//遍历(v1.size()+[])
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	//迭代器
	vector<int>::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	// 范围for
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

4、vector 增删查改

                      函数                                                    功能
⭐push_back() 尾插
pop_back() 尾删
⭐find() 查找
⭐insert (iterator position, const value_type& val)
指定位置position之前插入数据val
⭐erase (iterator position)
删除pos位置的数据
swap() 交换两个vector的数据空间

三、vector容器深度剖析及模拟实现

说明:对于vector容器的实现,我们模拟标准库<vector>中的实现方式,即在头文件(vector.h)中完成vector容器常用接口的实现。同时,为了我们实现的vector容器能够适用于不同的数据类型,我们采用类模板的形式。此外,为了避免命名的冲突,我们将所有的实现过程都放在一个我们自己的命名空间中。

我们想要模拟实现vector容器,那就要理解vector容器的底层结构。前面已经提到,其本质就是动态数组,在vector类中就有三个指向这片动态内存空间的指针(即vector类的三个成员变量)。

namespace hds 
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		//...
	private: // 成员变量(设定缺省值)
		iterator _start = nullptr; // 指向数组开头的指针
		iterator _finish = nullptr; // 指向数组最后一个元素后一个位置的指针
		iterator _end_of_storage = nullptr; // 指向数组空间最后一个位置的指针
	};
}

3.1、类对象的初始化

1、默认构造
// 默认构造函数
/*vector() 
{}*/

// C++11强制生成默认构造
vector() = default;
2、拷贝构造(⭐)
vector(const vector<T>& v)
{
	reserve(v.size());
	for (auto e : v)
	{
		push_back(e);
	}
}

这里v是const对象,所以size()函数必须是const成员函数,否则就会报错。

3、迭代器区间构造(⭐)

用迭代器区间初始化,同时用InputItrerator代替iterator,可以让函数模板不仅仅只能用来初始化vector对象。

// 类模板的成员函数还可以继续是函数模板
template<class InputIterator> 
vector(InputIterator first, InputIterator end)
{
	while (first != end)
	{
		push_back(*first);
		++first;
	}
}

测试:

void test05()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	print_vector(v);

	vector<int> v2(v.begin(), v.begin() + 3);
	print_container(v2);
	
    // list容器
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	print_container(lt);
	// 使用list容器初始化vector容器
	vector<int> v3(lt.begin(), lt.end());
	print_container(v3);
}
4、用n个val初始化
// 用n个val来初始化
vector(size_t n, const T& val = T())
{
	reserve(n);
	for (size_t i = 0; i < n; i++)
	{
		push_back(val);
	}
}

测试:

void test05()
{
	vector<string> v4(5, "abcd"); // 使用5个字符串"acbd"来初始化string类型的vector对象v4
	vector<int> v5(10); // 使用10个int类型的缺省值来初始化int类型的vector对象v5
	print_container(v4);
	print_container(v5);

	vector<int> v6(10u, 1); 
	print_container(v6);
}

使用10个1初始化,由于编译器默认都是int类型的参数,会优先调用函数模板来初始化,存在对整数的解引用(报错)。
解决方案:

1、重载一个函数:vector(int n, const T& val = T());让编译器优先选择调用该函数
2、在实参后面加上 u,声明实参是size_t(unsigned int)类型的

5、赋值重载——operator=(⭐)
// 传统写法
vector<T>& operator=(const vector<T>& v)
{
	if (_start != v._start)
	{
		clear();
		reserve(v.size());
		for (auto e : v)
		{
			push_back(e);
		}
	}
	return *this;
}
// 现代写法
void swap(const vector<T>& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_end_of_storage, v._end_of_storage);
}

vector<T>& operator=(const vector<T> v)
{
	swap(v);
	return *this;
}
4、析构函数

_start指向动态数组,用delete[] 释放动态申请的空间。

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

3.2、测试接口(用于打印数据)——print_Container

我们为了打印函数可以实现不同类型vector对象的打印,将其实现为函数模板。

规定,没有实例化的类模板里面取东西,编译器不能区分这里const_iterator是类型还是静态成员变量。用typename声明const_iterator是类型

template<class T>
void print_vector(const vector<T>& v)
{
	typename vector<T>::const_iterator it = v.begin();
	// auto it = v.begin(); // 也可以直接用auto
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

范围for+auto

template<class T>
void print_vector(const vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

采用Container,可以让打印函数模板适用于更多的容器,不仅仅只是vector。(推荐写法)

template<class container>
void print_Container(const container& v)
{
	for (auto e : v)
	{
    cout << e << " ";
	}
	cout << endl;
}

3.3、功能函数接口

1、迭代器(⭐)

对于不同的类型的指针,typedef重命名为不同的迭代器。

typedef T* iterator;
typedef const T* const_iterator;

当我们了解了vector容器的底层结构就是动态数组后,我们就可以快速地实现指向容器的一众迭代器了。

// 返回指向容器中第一个元素的迭代器
iterator begin()
{
	return _start;
}
// 返回指向容器中最后一个元素下一个位置的迭代器
itereator end()
{
	return _finish;
}
// 返回指向容器中第一个元素的迭代器(const对象)
const_iterator begin()const
{
	return _start;
}
// 返回指向容器中最后一个元素下一个位置的迭代器(const对象)
const_iterator end()const
{
	return _finish;
}
2、获取有效数据个数——_size

由于两点指针相减就是这两个指针之间的元素个数,求_size(有效元素个数),即让_finish减去_start就是有效元素的个数。

// const成员函数
size_t size()const
{
	return _finish - _start;
}
3、获取数组空间大小——_capacity
size_t capacity()const
{
	return _end_of_storage - _start;
}
4、判空——empty

根据_start和_finish指针是否指向同一个位置来判断。

bool empty()
{
	return _start == _finish;
}
5、访问操作符重载——operator[ ](⭐)

T& operator[](size_t pos)
{
	assert(pos < size());
	return *(_start + pos);
}

const对象

const T& operator[](size_t pos)const
{
	assert(pos < size());
	return *(_start + pos);
}
6、清理空间——clear

清理空间即将_start指向空间中的数据清除,但是并不释放空间,所以只需要让_finish指针指向_start指向的位置。

void clear()
{
	_finish = _start;
}
7、清除迭代器指向位置的数据——erase(⭐)

void erase(iterator pos)
{
	assert(pos < _finish);
	assert(pos >= _start);
	while (pos < _finish - 1)
	{
		*pos = *(pos + 1);
		pos++;
	}
	_finish--;
}

8、申请空间——reserve(⭐)

当我们需要扩容时,我们可以通过new的方式来另外开辟一块空间tmp,然后将_start指针指向空间中的数据拷贝到tmp空间,并释放_start指向的空间,最后让_start指针指向tmp空间,就实现了扩容。但是,如果我们用memcpy函数来拷贝数据时,只能实现对内置类型的浅拷贝,对于自定义类型(如string类对象的_str指向了资源),就需要深拷贝。

void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t old_size = size();
		iterator tmp = new T[n];
		// memcpy(tmp, _start, old_size * sizeof(T)); // 只能浅拷贝
		// 实现深拷贝
		for (size_t i = 0; i < old_size; i++)
		{
			tmp[i] = _start[i];
		}
		delete[] _start;
		_start = tmp;
		_finish = _start + old_size;//使用old_size,而size()函数由于_start=tmp更新了,此时_finish-_start已经不再表示有效数据个数(重点)
		_end_of_storage = _start + n;
	}
}

下面我们来感受一下拷贝的过程

void test06()
{
	vector<string> v0;
	// 插入四个字符串(不需要扩容)
	v0.push_back("abcdefg");
	v0.push_back("abcdefg");
	v0.push_back("abcdefg");
	v0.push_back("abcdefg");
	print_Container(v0);

	// 继续插入一个字符串(扩容)
	v0.push_back("abcdefg");
	print_Container(v0);
}

可以看到,当我们用vector创建一个string类类型的对象时,_start指向的空间中内置类型成员_str还指向了资源,所以,这时候我们想要扩容就要实现深拷贝。

9、扩容——resize(⭐)

当空间不够时还可以使用resize来扩容,resize在扩容的同时还会实现初始化。但是,当我们想要缩小空间时,resize只能减少有效数据个数,并不会减小capacity。同时,第二个参数我们使用缺省值。

void resize(size_t n, const T& val = T())
{
	if (n <= size())
	{
		_finish = _start + n;
	}
	else
	{
		reserve(n);
		while (_finish < _start + n)
		{
			*_finish = val;
			_finish++;
		}
	}
}

10、尾插——push_back(⭐)

想要插入数据,就要先判断空间是否足够,不够就需要扩容。

void push_back(const T& x)
{
	if (_finish == _end_of_storage)
	{
		size_t sz = capacity() == 0 ? 4 : 2 * capacity();
		reserve(sz);
		_end_of_storage = _start + sz;
	}
	*_finish = x;
	_finish++;
}
11、尾删——pop_back
void pop_back()
{
	assert(!empty());
	--finish;
}
12、指定位置插入——insert(⭐)
// 错误示范:
void insert(iterator pos, const T& x)
{
	assert(pos < _finish && pos >= _start);
    // 扩容
	if (_finish == _end_of_storage)
	{
		size_t sz = capacity() == 0 ? 4 : capacity() * 2;
		reserve(sz);
	}
	iterator end = _finish;
	// 将pos位置及之后的数据整体向后移动
    while (end > pos) {
		*end = *(end - 1);
		end--;
	}
	*pos = x; // 插入数据
	_finish++;
}

我们最容易用这样的代码去插入数据,下面我们来测试一下:

void test02() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	print_vector(v);

	auto p = find(v.begin(), v.end(), 3);
	p = v.insert(p, 30); // 在3的之前插入30
	print_vector(v);
	*(p + 1) *= 10; // 修改迭代器指向位置处的值
	print_vector(v);
}

输出结果:

我们发现,此时insert函数并没有实现在3之前插入30的效果,这就是因为迭代器失效而引起的。

那为什么会迭代器失效呢?

因为,当我们在插入了1,2,3和4这四个数据后,此时_start指向的数组空间被有效数据占满了,即size()=capacity()。当我们再想在3之前插入30时,就需要扩容,扩容会将原来_start指向的空间释放,而迭代器pos指向原来空间中的3,这就导致了迭代器失效。这时候我们就要注意:pos就像野指针一样指向随机的位置,我们不能再访问pos指向位置的值。所以,我们想要访问pos,或者在pos位置插入数据,就必须更新迭代器。

更新迭代器,我们可以通过记下pos迭代器相对于_start的位置,然后在扩容之后让pos迭代器指向新空间中对应的位置。同时,如果我们想要继续使用pos迭代器,我们可以让insert函数返回pos迭代器。

iterator insert(iterator pos, const T& x)
{
	assert(pos < _finish && pos >= _start);
	if (_finish == _end_of_storage)
	{
		size_t p = pos - _start; // 记下迭代器对于_start的相对距离
		size_t sz = capacity() == 0 ? 4 : capacity() * 2;
		reserve(sz);
		pos = _start + p; // 更新迭代器
	}
	iterator end = _finish;
    // 移动数据
	while (end > pos) {
		*end = *(end - 1);
		end--;
	}
	*pos = x;  // 插入
	_finish++;
    return pos; // 返回迭代器
}

再次测试:

四、完整源码

头文件:vector.h

#include<iostream>
using namespace std;
#include<assert.h>
#include<vector>
#include<string>
#include<list>

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

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

		// this = v
		vector(const vector<T>& v)
		{
			reserve(v.size());
			for (auto e : v)
			{
				push_back(e);
			}
		}

		// 类模板的成员函数还可以继续是函数模板
		template<class InputIterator> 
		/* 用迭代器区间初始化,同时用InputItrerator代替iterator,可以让函数模板不仅仅只能用来初始化vector对象*/
		vector(InputIterator first, InputIterator end)
		{
			while (first != end)
			{
				push_back(*first);
				++first;
			}
		}
		// 用n个val来初始化
		vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

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

		void clear()
		{
			_finish = _start;
		}

		// 传统写法
		/*vector<T>& opereator = (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._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}
		// 现代写法
		vector<T>& operator=(vector<T> v) // 这里用传值的方式,(函数调用结束,栈帧销毁)防止在交换的时候改变v的值
		{
			swap(v);
			return *this;
		}

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

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end()const
		{
			return _finish;
		}

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

		T& operator[](size_t pos)
		{
			assert(pos < size());
			return *(_start + pos);
		}

		const T& operator[](size_t pos)const
		{
			assert(pos < size());
			return *(_start + pos);
		}

		void resize(size_t n, T val = vector())
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);
				while (_finish<_start+n)
				{
					*_finish = val;
					_finish++;
				}
			}
		}
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();
			    iterator tmp = new T[n];
				// memcpy(tmp, _start, old_size * sizeof(T));
				/* memcpy只能实现对内置类型的浅拷贝,对于自定义类型(如string类对象的_str指向了资源),就需要深拷贝*/
				// 实现深拷贝
				for (size_t i = 0; i < old_size; i++)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;
				_start = tmp;
				_finish = _start + old_size;//使用old_size,而size()函数由于_start=tmp更新了,此时_finish-_start已经不再表示有效数据个数(重点)
				_end_of_storage = _start + n;
			}
		}

		void push_back(const T& a)
		{
			if (_finish == _end_of_storage)
			{
				size_t sz = capacity() == 0 ? 4 : capacity() * 2;
				reserve(sz);
				_end_of_storage = _start + sz;
			}
			*_finish = a;
			++_finish;
		}


		void earse(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			while (pos < _finish-1)
			{
				*pos = *(pos + 1);
				pos++;
			}
			_finish--;
		}


		bool empty()
		{
			return _start == _finish;
		}
		
		void pop_back()
		{
			assert(!empty());
			--_finish;
		}
	    //插入,同时将pos作为返回值返回,防止迭代器失效
		iterator insert(iterator pos, const T& a)
		{
			
			if (_finish == _end_of_storage)
			{
				size_t n = pos - _start; //用来更新迭代器
				size_t sz = capacity() == 0 ? 4 : 2 * capacity();
				reserve(sz);
				pos = _start + n; // 更新迭代器
			}
			iterator end = _finish - 1;
			
			while (end >= pos)
			{
				*(end+1) = *end;
				end--;
			}
			*pos = a;
			_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声明const_iterator是类型
		typename vector<T>::const_iterator it = v.begin();
		// auto it = v.begin(); // 也可以直接用auto
		while (it != v.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		// 方法二:(重点)
		/*for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;*/
	}
	// 采用Container,可以让打印函数模板适用于更多的容器,不仅仅只是vector
	template<class Container>
	void print_container(const Container& v)
	{
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

测试代码:test.cpp

namespace hds
{
    void test01()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
		print_vector(v);
		v.insert(v.begin() + 1, 0);
		print_vector(v);
	}
	void test02()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
		print_vector(v);

		int x;
		cin >> x;
		auto p = find(v.begin(), v.end(), 2);
		p = v.insert(p, 30);
		print_vector(v);
		// insert以后p就是失效,不要直接访问,要访问就要更新这个失效的迭代器的值,可以用insert函数返回pos并用p接收,更新迭代器p的值
		*(p+1) *= 10;
		print_vector(v);
	}

	void test03()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(1);
		v.push_back(1);
		v.push_back(1);
		print_vector(v);

		v.resize(10, 2);
		print_vector(v);

		v.resize(2, 3);
		print_vector(v);
	}

	void test04()
	{
		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);
		print_vector(v);

		auto it = v.begin();
		while (it!=v.end())
		{
			if (*it % 2 == 0)
			{
				v.earse(it);
			}
			else
			{
				it++;
			}
		}
		print_vector(v);
	}

	void test05()
	{
		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);
		print_vector(v);

		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);

		v = v1;
		print_container(v);
		print_container(v1);

		vector<int> v2(v.begin(), v.begin() + 3);
		print_container(v2);
		// list容器
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		print_container(lt);
		// 使用list容器初始化vector容器
		vector<int> v3(lt.begin(), lt.end());
		print_container(v3);

		vector<string> v4(5, "abcd"); // 使用5个字符串"acbd"来初始化string类型的vector对象v4
		vector<int> v5(10); // 使用10个int类型的缺省值来初始化int类型的vector对象v5
		print_container(v4);
		print_container(v5);

		vector<int> v6(10u, 1); // 使用10个1初始化,由于编译器默认都是int类型的参数,会优先调用函数模板来初始化,存在对整数的解引用(报错)
		// 解决方案:1、重载一个函数:vector(int n, const T& val = T());让编译器优先选择调用该函数
		// 2、在实参后面加上 u,声明实参是size_t(unsigned int)类型的
		print_container(v6);
	}

	void test06()
	{
		vector<string> v0;
		// 插入四个字符串(不需要扩容)
		v0.push_back("abcdefg");
		v0.push_back("abcdefg");
		v0.push_back("abcdefg");
		v0.push_back("abcdefg");
		print_container(v0);

		// 继续插入一个字符串(扩容)
		v0.push_back("abcdefg");
		print_container(v0);
	}
}

int main()
{ 
    hds::test06();
    return 0;
}

本期的分享就到此结束,大家快去上手练习吧!!!如果觉得还不错,请大家点个赞支持一下吧(笔芯笔芯)。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐