C++中vector的模拟实现

目录

1.打印函数的模板

1.1专门打印vector类对象的模板

1.2适用于所有支持++的迭代器打印函数

2.vector类的结构

3.默认成员函数

3.1构造函数

3.1.1默认构造函数

3.1.2拷贝构造函数 

3.1.3其他构造函数

3.1.3.1通过迭代器区间进行构造

3.1.3.2fill构造函数 

3.2赋值运算符重载

3.3析构函数

4. vector类的迭代器(Iterators)

5. vector类的空间操作(Capacity)

5.1size()

5.2capacity()

5.3empty()

5.4resize()

5.5reserve()

5.5.1使用memcpy()进行拷贝数据造成的问题

6.元素访问(Element access) 

6.1operator[]

7.vector类的修改操作(Modifiers)

7.1push_back()

7.2pop_back() 

7.3insert()

7.3.1第一种迭代器失效

7.3.2第二种迭代器失效 

7.4erase() 

7.5swap()

7.6clear() 

8.参考代码 

8.1vector.h

 8.2test.cpp

 


  vector的实现和string其实比较类似,了解vector的功能可以参考C++函数网址C++中vector类的使用,对比string可以参考C++中string类的模拟实现

1.打印函数的模板

1.1专门打印vector类对象的模板

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

		//用::从类中取对象能取到的有静态成员变量和typedef后的类型
		//从没有实例化的类模板里面取东西,编译器不能区分这里的const_iterator是类型还是静态成员变量
		//typename vector<T>::const_iterator it = v.begin();
		//auto it = v.begin();
		//while (it != v.end())
		//{
		//	cout << *it << " ";
		//	it++;
		//}
		//cout << endl;
	}

        这里给模板里面传入一个vector的类对象,函数中第一种方式是通过for范围进行遍历打印,第二种方式是通过迭代器的方式进行遍历打印。需要注意的是,这里从没有实例化的类模板里面取东西,可能取到的是静态变量或类型,所以为了区分取到的是类型,这里在vector<T>::const_iterator之前加上typename来表示是从类里面取类型。

1.2适用于所有支持++的迭代器打印函数

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

		//typename vector<T>::const_iterator it = v.begin();
		//auto it = v.begin();
		//while (it != v.end())
		//{
		//	cout << *it << " ";
		//	it++;
		//}
		//cout << endl;
	}

        这里把传入的模板当作类型参数,即可以用这里函数遍历打印任意支持++操作的容器。

2.vector类的结构

        vector里面是通过三个指针来维护一个数组的

		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;

        _start指向数组的开始位置,_finish指向有效数据的下一个位置,_end_of_storage指向的是数组容量的结束位置。

3.默认成员函数

        这里的构造函数及赋值运算符重载的实现,大量使用的复用的方式,而不是传统的实现方式。

3.1构造函数

3.1.1默认构造函数

        vector在这里是使用3个指针进行维护的,3个指针也给了nullptr的初始值,在初始化列表的时候就会进行初始化定义,所有这里的默认构造函数可以不写。或者使用以下两种写法也行。

		//vector()
		//{}

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

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

3.1.2拷贝构造函数 

        使用reserve()函数先开辟一个与v一样大的空间,然后通过push_back()函数对v进行遍历拷贝到this中。

		vector(const vector<T>& v)
		{
            //开辟与v一样大的存储空间
			reserve(v.size());    //这里复用后面实现的reserve()函数进行空间的开辟
			for (auto& e : v)
			{
				push_back(e);
			}
		}

3.1.3其他构造函数

3.1.3.1通过迭代器区间进行构造

        在下述代码中将这种构造函数写成了一种函数模板的形式,是为了支持通过其他结构的迭代器对该迭代器进行初始化构造。使用该构造函数时,传入支持++操作的数据结构迭代器则能构造vector对象。

        注:虽然可以通过其他数据结构的迭代器对vector对象进行初始化,但是两个容器存储的数据类型需要是相同数据类型,不然会出错。

		//类模板的成员函数,还可以继续是函数模板
		//任意容器迭代器初始化,要求类型是匹配的
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)	//vector这里可以写成小于,因为是连续的空间,但是像链表的话不是连续的空间,为了支持所有结构的迭代器,这里写成!=
			{
				push_back(*first);
				++first;
			}
		}
3.1.3.2fill构造函数 
		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 (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

        为什么要重载成两个函数的原因如下:

        当只有第一个重载时,通过下列的方式进行构造会匹配到使用迭代器区间进行构造,则会报错。

        原因是因为输入的10,1默认是int类型,如匹配fill构造函数的话,int到size_t有一步类型转换,对于编译器来说这样的转换可能会发生错误,所有匹配到迭代器区间进行构造,因为传入模板的是两个int类型,这样对于fill构造函数来说是更好的匹配上了。但是由于匹配上了迭代器区间构造,在该函数中迭代器变成了int类型,不能进行解引用操作,所有会报错。

	void test_vector8()
	{
		//这样写会匹配到迭代器区间初始化,因为迭代器区间初始化实例化出来形参是两个int类型,更加匹配
		vector<int> v6(10, 1);
		print_container(v6);
	}

        所有写两个函数构成重载是一种解决的方式,另一种解决方式是使用时写成如下代码,声明传入的是size_t类型的参数。

		vector<int> v6(10u, 1);	//将形参第一个加上u,更加匹配size_t类型
		print_container(v6);

3.2赋值运算符重载

        1.传统写法

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

			return *this;
		}

        2.现代写法 

    void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		//因为是传值传参,所有交换后形参v改变,但是不影响外面的实参
		//vector<T>& operator=(vector<T> v)
		//类里面可以用类名替代类型 vector是类的名字, vector<T>是一种数据类型
		vector& operator=(vector v)
		{
			swap(v);

			return *this;
		}

3.3析构函数

        vector的结构是通过三个指针进行维护的,所以析构的时候释放申请的空间,然后将三个指针置为nullptr即可。 即使是里面存储的是自定义类型,需要申请空间的自定义类型,在析构的时候也会调用自身的析构函数。

		~vector()
		{
			delete[] _start;
			_start = nullptr;
			_finish = nullptr;
			_end_of_storage = nullptr;
		}

4. vector类的迭代器(Iterators)

        vector底层是通过数组结构实现的,所以它的迭代器和string一样,使用原生指针即可。

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;
		}

5. vector类的空间操作(Capacity)

5.1size()

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

5.2capacity()

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

5.3empty()

		bool empty() const
		{
			return _start == _finish;
		}

5.4resize()

		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;
				}
			}
		}

        分为两种情况:

        1.当n < size():保留数组中的前n个数据即可。

        2.当n > size(): 通过reserve()函数将空间扩大到n个,然后从_finish开始添加新插入的数据。

5.5reserve()

		void reserve(size_t n)
		{
            //这里n大于原来的空间才需要扩容
			if (n > capacity())
			{
				size_t old_size = size();	//先用原来的finish和start算出size,不然后面更新finish的时候会造成_start已经变为了更新后的值了 
				//开新空间--当存储的是自定义类型是,开辟的空间中就行调用自定义类型的默认构造进行初始化
				T* tmp = new T[n];
				//拷贝数据到新的vector中
				//memcpy(tmp, _start, size() * sizeof(T));	这里如果vector里面是一个需要深拷贝的类型,就会出错
				for (size_t i = 0; i < old_size; i++)
				{
					tmp[i] = _start[i];
				}
				//释放旧空间,这时候_start, _finish, _end_of_storage都为空指针
				delete[] _start;
				//更新结构中对应的值
				_start = tmp;
                //这里如果没有记录扩容之前的size,使用size()是扩容之后的size了_finish = _start + size() = _start + _finish - _start,相当于_finish还是为0(空指针)
                //_finish = _start + size();
				_finish = tmp + old_size;
				_end_of_storage = tmp + n;
			}
		}

5.5.1使用memcpy()进行拷贝数据造成的问题

        这里如果通过memcpy进行拷贝的时候进行的也是浅拷贝,当存储的数据是内置类型的时候是没有问题的,但是如果存储的数据为自定义类型(比如string这种涉及到资源管理的类型)时,就会出错。 

        vecotor实现的push_back()在扩容的时候也是复用的reserve()函数,这里以vector里面存储string类型的元素为例子,当原本vector中存储了4个string对象,插入第五个时,vector要进行扩容到8个,然后将数据拷贝到新空间中,但是当使用memcpy进行数据的拷贝时,拷贝的是vector原空间中指向string对象的指针_str,然后进行到delete[]这一步的时候,vector对象中的string对象会调用自己的析构函数释放空间,此时,新vector中的string对象里面的_str被置为了空指针,所以拷贝到vector的4个string对象都已经成为了随机值。

        解决方式就是将vector对象中的string对象一个一个通过string对象的赋值运算重载进行拷贝。string中的赋值运算就是释放原空间,开辟新空间与新的string对象一样大的空间,进行拷贝。

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

         string的赋值运算:

		string operator=(const string& s)
		{
			//对已有的对象进行赋值运算
			if (this != &s)	//如果自己给自己赋值,则直接返回*this 
			{
				//1.先释放原数组指针指向的空间 
				delete[] _str;
				//重新申请一个与s._str指向空间相同的空间
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
				_size = s._size;
				_capacity = s._capacity;
			}

			return *this;
		}

6.元素访问(Element access) 

6.1operator[]

		//为了支持使用下标遍历
		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}

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

        其他接口很容易实现,这里就不过多的进行描述了。 

7.vector类的修改操作(Modifiers)

7.1push_back()

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

7.2pop_back() 

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

7.3insert()

7.3.1第一种迭代器失效

        下列这段代码有迭代器失效的问题,vector的迭代器是原始指针,当插入数据要进行扩容的时候,pos还是指向原空间的指针,但是现在vector已经是在一段新空间中了,旧的空间已经释放了,此时的pos就失效了,变成了野指针。

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//扩容
			if (_finish == _end_of_storage)
			{
				reserve(capacity() == 0 ? 4 : 2 * capacity());
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{ 
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

        解决方法:

        记录扩容之前pos和_start的相对位置,扩容之后_start进行了更新,pos则用更新后的_start加上相对位置即可。

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//扩容
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				pos = _start + len;
			}
            //挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{ 
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

7.3.2第二种迭代器失效 

         解释写在了注释中了。

void test_vector2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);

		int x;
		cin >> x;
		//所有迭代器都是左闭右开,不会到v1.end()
		auto pos = find(v1.begin(), v1.end(), x);
		if (pos != v1.end())
		{
			v1.insert(pos, 40);
			//*(pos) *= 10;
			//本来想表达的意思是在x之前插入40,然后再让x*10,
			//插入之后,此时的pos指向的是40
			//这也是一种迭代器失效

			//如果遇到扩容时,pos指向旧空间,也不是指向的40了

			//所以,insert以后pos就失效了,不要访问
			//insert内部进行修正,但是在外部进行访问pos,pos没有被修正
			//形参的改变不影响实参
			//vs下的pos这时强制检查,不能访问
			//g++不进行强制检查
		}

		print_container(v1);
	}

7.4erase() 

        这里的erase()函数进行删除之后,pos就自动指向了被删除元素的下一个元素。

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

			iterator it = pos + 1;
			while (it != end())
			{
				*(it - 1) = *it;
				++it;
			}

			--_finish; 
		}

7.5swap()

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

7.6clear() 

		void clear()
		{
			_finish = _start;
		}

8.参考代码 

        这里所以函数的实现和测试代码我也一并写在了vector.h里面了。

8.1vector.h

#pragma once
#include<assert.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
#include<string>
using namespace std;
namespace XiaoC
{
	template<class T>
	class vector
	{
	public:

		//vector()
		//{}

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

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

		//类模板的成员函数,还可以继续是函数模板
		//任意容器迭代器初始化,要求类型是匹配的
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)	//vector这里可以写成小于,因为是连续的空间,但是像链表的话不是连续的空间,为了支持所有结构的迭代器,这里写成!=
			{
				push_back(*first);
				++first;
			}
		}

		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 (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		void clear()
		{
			_finish = _start;
		}

		//传统写法
		//vector<T>& 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._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		//因为是传值传参,所有交换后形参v改变,但是不影响外面的实参
		//vector<T>& operator=(vector<T> v)
		//类里面可以用类名替代类型 vector是类的名字, vector<T>是一种数据类型
		vector& operator=(vector v)
		{
			swap(v);

			return *this;
		}

		~vector()
		{
			delete[] _start;
			_start = nullptr;
			_finish = nullptr;
			_end_of_storage = nullptr;
		}

		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;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();	//先用原来的finish和start算出size,不然后面更新finish的时候会造成_start已经变为了更新后的值了 
				//开新空间
				T* tmp = new T[n];
				//拷贝数据到新的vector中
				//memcpy(tmp, _start, size() * sizeof(T));	这里如果vector里面是一个需要深拷贝的类型,就会出错
				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;
			}
		}

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

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

		bool empty() const
		{
			return _start == _finish;
		}

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

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

		//有效迭代器pos不可能为0
		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			//扩容
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				pos = _start + len;
			}
			iterator end = _finish - 1;
			//这里如果遇到扩容的情况,则_start指向的空间已经不是原空间了,是新开的空间,而pos指向的还是原来空间中的pos,所以会发生迭代器失效
			//这种迭代器失效类似与野指针
			//解决方案:在扩容前记录pos与_start的相对位置,扩容之后更新pos的值
			//挪动数据
			while (end >= pos)
			{ 
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

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

			iterator it = pos + 1;
			while (it != end())
			{
				*(it - 1) = *it;
				++it;
			}

			--_finish; 
		}

		// 自定义给缺省值的方式,调用默认构造给缺省值
		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;
				}
			}
		}

		//为了支持使用下标遍历
		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}

		const T& operator[](size_t i) const
		{
			assert(i < size());
			return _start[i];
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};

	//const修饰的参数要用const迭代器
	//void print_vecotr(const vector<int>& v)
	//{
	//	for (auto& e : v)
	//	{
	//		cout << e << " ";
	//	}
	//	cout << endl;

	//	vector<int>::const_iterator it = v.begin();
	//	while (it != v.end())
	//	{
	//		cout << *it << " ";
	//		it++;
	//	}
	//	cout << endl;
	//}

	//将打印函数改造成模板
	template<class T>
	void print_vector(const vector<T>& v)
	{
		for (auto& e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		//用::从类中取对象能取到的有静态成员变量和typedef后的类型
		//从没有实例化的类模板里面取东西,编译器不能区分这里的const_iterator是类型还是静态成员变量
		//typename vector<T>::const_iterator it = v.begin();
		//auto it = v.begin();
		//while (it != v.end())
		//{
		//	cout << *it << " ";
		//	it++;
		//}
		//cout << endl;
	}

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

		//typename vector<T>::const_iterator it = v.begin();
		//auto it = v.begin();
		//while (it != v.end())
		//{
		//	cout << *it << " ";
		//	it++;
		//}
		//cout << endl;
	}

	void test_vector1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

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

		print_container(v1);
	}

	void test_vector2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		//print_vecotr(v1);

		//v1.insert(v1.begin() + 2, 20);

		print_container(v1);

		int x;
		cin >> x;
		//所以迭代器都是左闭右开,不会到v1.end()
		auto pos = find(v1.begin(), v1.end(), x);
		if (pos != v1.end())
		{
			v1.insert(pos, 40);
			//*(pos) *= 10;
			//本来想表达的意思是在x之前插入40,然后再让x*10,
			//插入之后,此时的pos指向的是40
			//这也是一种迭代器失效

			//如果遇到扩容时,pos指向旧空间,也不是指向的40了

			//所以,insert以后pos就失效了,不要访问
			//insert内部进行修正,但是在外部进行访问pos,pos没有被修正
			//形参的改变不影响实参
			//vs下的pos这时强制检查,不能访问
			//g++不进行强制检查
		}

		print_container(v1);
	}

	void test_vector3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(4);
		v1.push_back(5);

		print_container(v1);

		//删除所有的偶数
		auto it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				v1.erase(it);
			}
			else
			{
				it++;
			}
		}

		print_container(v1);
	}

	void test_vector4()
	{
		//内置类型的默认构造
		int i = int();
		int j = int(1);
		int k(2);

		vector<int> v;
		v.resize(10, 1);
		v.reserve(20);
		print_container(v);
		cout << v.size() << endl;
		cout << v.capacity() << endl;

		v.resize(15, 2);
		print_container(v);

		v.resize(25, 3);
		print_container(v);

		v.resize(5);
		print_container(v);
	}

	void test_vector5()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);
		
		vector<int> v2 = v1;
		print_container(v2);

		vector<int> v3;
		v3.push_back(10);
		v3.push_back(20);
		v3.push_back(30);

		v1 = v3;
		print_container(v1);
	}

	void test_vector6()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);

		vector<int> v2(v1.begin(), v1.begin() + 3);
		print_container(v1);
		print_container(v2);

		list<int> lt;
		lt.push_back(10);
		lt.push_back(10);
		lt.push_back(10);
		lt.push_back(10);
		lt.push_back(10);
		vector<int> v3(lt.begin(), lt.end());
		print_container(lt);
		print_container(v3);

		vector<string> v4(10, "111111");
		print_container(v4);

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

		//这样写会匹配到迭代器区间初始化,因为迭代器区间初始化实例化出来形参是两个int类型,更加匹配
		//vector<int> v6(10, 1);
		//print_container(v6);

		//解决方案1
		//vector<int> v6(10u, 1);	//将形参第一个加上u,更加匹配size_t类型
		//print_container(v6);

		//解决方案2,多重载几个构造
		vector<int> v7(10, 1);
		print_container(v7);
	}

	void test_vector7()
	{
		vector<string> v;
		v.push_back("11111111111111111111111");
		v.push_back("11111111111111111111111");
		v.push_back("11111111111111111111111");
		v.push_back("11111111111111111111111");
		print_container(v);

		v.push_back("11111111111111111111111");
		print_container(v);

		//这里的原因是因为扩容中用memcpy进行拷贝,是浅拷贝
		//当前vector存的是string,string中的_str指向空间,memcpy拷贝的_str这个指针
		//所有,当扩容之后,之前的空间释放了,_str就是野指针,打印出来就是随机值
	}

}

 8.2test.cpp

#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"

int main()
{
	//XiaoC::test_vector1();
	//XiaoC::test_vector2();
	//XiaoC::test_vector3();
	//XiaoC::test_vector4();
	//XiaoC::test_vector5();
	//XiaoC::test_vector6();
	//XiaoC::test_vector7();

	return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值