【C++】vector的简单使用和模拟实现

目录

构造: 

扩容机制:

插入insert():

  vector<>中是模版,模版可使用多种类型,所以vector可以传多种类型:

这句代码是什么意思?

​编辑

几个例题:

1、只出现一次的数字:

解释:

2、杨辉三角

代码逐段解析

示例

复杂度

边界情况处理

模拟实现vector精简版(有瑕疵)注重了解周边知识

头插push_back()、vector大小size()、vector容量capacity():

问题1:

~vector()析构函数

iterator begin()、end()迭代器

测const vector容器

测试函数print_vector()

尾删pop_back()、判空empty()

插入函数insert()、扩容reserve()(无初始化)、扩容resize()(会初始化)

删除某个位置erase()

指定大小并且resize()

拷贝构造vector(const vector& v)

赋值vector::operator=、交换swap()

迭代器区间构造:template

vector (size_type n, const value_type& val = value_type())

c++11支持的用法:

​编辑initializer_list,支持迭代器,本质是可认为x是一个常量数组,其中有两个指针,分别指向开始begin()和结束end()​编辑

initializer_list 的构造函数

修复扩容的bug

正确做法:使用循环逐个拷贝

示例说明

结论

insert()导致迭代器失效

erase()会不会导致迭代器失效?会,不能使用迭代器

  ​编辑erase()更新:查看文档:erase()会返回删除元素的下一个元素的迭代器。​编辑

首先先简单的讲解vector的几个方法:

构造: 

示例:

push_back();

int main()
{
	vector<int> v;
	//v.push_back(1);
	//v.push_back(2);
	//v.push_back(3);
	//v.push_back(4);
	//v.push_back(5);
	vector<int> v(10, 1);

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

	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	for (auto e : v)
	{ 
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

扩容机制:

void test_vector2()
{
	vector<int> v;
	size_t sz = v.capacity();
	//v.reserve(100);
	// 提前将容量设置好,可以避免一边插入一边扩容
	cout << "making bar 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';
		}
	}
	vector<int> a;
	//开好空间想直接初始化,可以用resize()
	a.resize(10,0);
	for (auto e : a)
	{
		cout << e << " ";
	}
	cout << endl;
}

vs下一般1.5倍取整,linux一般2倍

插入insert():

想在某个数字前插入,那需要知道这个数字所处位置,但是vector没有find(),因此我们用到算法库中的find()

算法库头文件:

#include<algorithm>

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

	//这里打印一下整个区间
	for (auto e : v )
	{
		cout << e << " ";
	}
	cout << endl;

	//在这个数组空间内寻找3
	//vector<int>::iterator pos = find(v.begin(), v.end(), 3);
	auto pos = find(v.begin(), v.end(), 3);

	if (pos != v.end())
	{
		v.insert(pos, 30);
	}
	cout << endl;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}void test_vector3()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);

	//这里打印一下整个区间
	for (auto e : v )
	{
		cout << e << " ";
	}
	cout << endl;

	//在这个数组空间内寻找3
	//vector<int>::iterator pos = find(v.begin(), v.end(), 3);
	auto pos = find(v.begin(), v.end(), 3);

	if (pos != v.end())
	{
		v.insert(pos, 30);
	}
	cout << endl;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

想要头插

	v.insert(v.begin(), 7);

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

指定下标位置插入:

//插入到第二个位置
v.insert(v.begin() + 1, 0);

for (auto e : v)
{
	cout << e << " ";
}
cout << endl;

插入迭代器区间:

可以不插入自己的迭代器区间,可以插入其他容器的,只要数据类型匹配就可以(会隐式类型转换)。

//插入迭代器区间
string s("abcd");
//插入到末尾
v.insert(v.end(), s.begin(), s.end());

for (auto e : v)
{
	cout << e << " ";
}
cout << endl;

结果:

为什么vector可以用算法的find(),但是string我们要自己写find()?

因为string需要支持子串的查找,和vector ,list是不一样的。

  vector<>中是模版,模版可使用多种类型,所以vector可以传多种类型:

void test_vector()
{
	//前面的都是整形数组,而这里是一个对象数组
	vector<string> v;
	//每个对象是一个vector
	string s1("苹果");
	//有名对象
	v.push_back(s1);
	//匿名对象
	v.push_back(string("香蕉"));
	//隐式类型转换---生成临时对象
	v.push_back("草莓");

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

这句代码是什么意思?

	vector<vector<int>> vv;

如图:相当于这个对象的_a 类型是vector<int>*,这个_a中的_a的类型是int*,类似于二维数组,二维数组内,就有许多一维数组

 

如何访问vector的第i行的第j个数据?

vv[i][j]  ---->返回vector<int> 对象:vv.operator()[i]    ---> vv.operator()[i].operator()[j] 返回int对象。

即可访问

int a[5][10]   ----> a[i][j]本质转换成指针解引用(  *(*(a+i)+j)  )

几个例题:

1、只出现一次的数字

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

  • 交换律a ^ b = b ^ a

  • 结合律a ^ (b ^ c) = (a ^ b) ^ c

  • 自反性a ^ a = 0

  • 与 0 的异或a ^ 0 = a

代码的工作原理:

  1. 初始化value 被初始化为 0。

  2. 遍历数组:对于数组中的每个元素 e,执行 value ^= e,即将 value 与 e 进行异或操作。

    • 如果 e 是第一次出现,value 会变成 e

    • 如果 e 是第二次出现,value 会变成 value ^ e,由于 e ^ e = 0,所以 value 会变回 0。

  3. 最终结果:由于数组中只有一个数字出现一次,其他数字都出现两次,最终 value 会存储那个只出现一次的数字。

2、杨辉三角

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv;
        //开空间并且初始化
        //reserve(),并没有初始化
        vv.resize(numRows);//开辟行数的空间
        for(size_t i = 0;i < vv.size();++i)
        {
            vv[i].resize(i+1,0);//开辟列数的空间,第0行有1个数据,第1行2个数据所以要加1,默认值为0
            //vv[i].size() - 1 = i
            vv[i][0] = vv[i][vv[i].size() - 1] = 1;
        }

        //遍历
        for(size_t i = 0; i < vv.size(); ++i)
        {
            for(size_t j = 0 ; j < vv[i].size(); ++j)
            {
                if(vv[i][j] == 0)
                {
                    vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
                }
            }
        }

        return vv;
    }
};

代码逐段解析

  1. 初始化二维数组

    vector<vector<int>> vv;
    vv.resize(numRows); // 创建numRows行
    for(size_t i = 0; i < vv.size(); ++i) {
        vv[i].resize(i+1, 0); // 每行有i+1列,初始化为0
        vv[i][0] = vv[i][i] = 1; // 首尾置1
    }
    • 每行的长度递增(i+1),初始化为全0。

    • 每行的首(vv[i][0])和尾(vv[i][i])元素设为1。

  2. 填充中间元素

    for(size_t i = 0; i < vv.size(); ++i) {
        for(size_t j = 0; j < vv[i].size(); ++j) {
            if(vv[i][j] == 0) { // 中间未填充的元素
                vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
            }
        }
    }
    • 遍历所有元素,若值为0(即中间元素),则通过上一行(i-1)的当前列(j)和前一个列(j-1)之和填充。

示例

以生成3行杨辉三角为例:

  1. 初始化

    • 行0:[1]

    • 行1:[1, 1]

    • 行2:[1, 0, 1]

  2. 填充中间值

    • 行2的中间元素:0 → 1+1=2,结果为[1, 2, 1]

复杂度

  • 时间复杂度:O(n²),需要遍历所有元素填充。

  • 空间复杂度:O(n²),存储整个杨辉三角。

边界情况处理

  • numRows=0:返回空数组。

  • numRows=1:返回单行[[1]]

模拟实现vector精简版(有瑕疵)注重了解周边知识

普通构造vector()

头插push_back()、vector大小size()、vector容量capacity():

#include<iostream>

#include<assert.h>
namespace bit
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;

        vector()
        {}

        size_t size()
        {
            return _finish - _start;
        }

        size_t capacity()
        {
            return _endofstorage - _start;
        }

        T& operator[](size_t pos)
        {
            assert(pos < size());
            return _start[pos];
        }
      
 void push_back(const T& val)
        {
            if (_finish == _endofstorage)//满了就需要扩容
            {
                //需要知道当前的空间大小就需要增加两个函数size、capacity

                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;

                T* tmp = new T[newcapacity];
                memcpy(tmp, _start, size() * sizeof(T));
            
                delete[] _start;
                _start = tmp;
              
 // 运行到这里的时候_start已经被释放并且重新赋值
                // 指向了tmp所指向的位置,而_finish还是处于原来的内存空间,所以   
                // 这时候计算size(),即_finish - _start,会出现指针算术错误,因为两者不属于同一块内存。

                _finish = tmp + size();
                _endofstorage = tmp + newcapacity;
            }
            *_finish = val;
            ++_finish; 

        }

    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };

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

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

问题1:

通过分析阅读以上代码,可以知道在释放_start的时候,应该先保存旧size()的大小,因此我们需要设置一个新的变量来存旧size()的大小

void push_back(const T& val)
{
	if (_finish == _endofstorage)//满了就需要扩容
	{
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		size_t old_size = size();
		T* tmp = new T[newcapacity];
		memcpy(tmp, _start, old_size * sizeof(T));
		delete[] _start;
		_start = tmp;
		_finish = tmp + old_size;
		_endofstorage = tmp + newcapacity;
	}
	*_finish = val;
	++_finish; 
}

~vector()析构函数

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

		}

iterator begin()、end()迭代器

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

测const vector容器

#include<iostream>

#include<assert.h>

namespace bit
{
	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;
		}

		vector()
		{}

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

		}

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

		size_t capacity() const
		{
			return _endofstorage - _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 push_back(const T& val)
		{
			if (_finish == _endofstorage)//满了就需要扩容
			{


				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				size_t old_size = size();
				T* tmp = new T[newcapacity];
				memcpy(tmp, _start, old_size * sizeof(T));
				delete[] _start;
				_start = tmp;
			
				_finish = tmp + old_size;
				_endofstorage = tmp + newcapacity;
			}
			*_finish = val;
			++_finish; 

		}

	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endofstorage = nullptr;
	};

}

测试函数print_vector()

需要用到模版,以便于使用到不同的类型

//template<typename T> //定义模版
template<class T> //定义模版 -- 新版

//template<typename T> //定义模版
template<class T> //定义模版 -- 新版

void print_vector(const vector<T>& v)
{

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

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

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

	for (auto e : v)
	{
		cout << e << " ";

	}
	cout << endl;
}

请注意:

出现这种问题的原因是因为

编译器不认识这一块的类型就会出现这样的报错,而这里出错的原因在于:

模版出现在一个地方只有已经被实例化了才具备意义,此时vector<T>还未被实例化,

一个类里面的内嵌类型或者静态成员变量,由于vector<T>不具备意义编译器不会去找,因此不能区分const_iterator是类型还是静态成员变量:解决办法: 

//typename表明后面是一个类型,编译会先通过,等在后面实例化了再取,再去找
typename vector<T>::const_iterator it = v.begin();

所以用auto很方便,编译器直接知道这里是一个类型。

尾删pop_back()、判空empty()

void pop_back()
{
	assert(empty());
	--_finish;//不用去删数据直接--尾部位置就可以,为空不能--,所以需要函数判空empty()
}

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

插入函数insert()、扩容reserve()(无初始化)、扩容resize()(会初始化)

可看见这里实际上就是原来写push_back()的代码,所以push_back()的代码可以改为:

void push_back(const T& val)
{
	if (_finish == _endofstorage)//满了就需要扩容
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}
	*_finish = val;
	++_finish; 

}

void insert(iterator pos, const T& val)
{
	assert(pos >= _start);
	assert(pos <= _finish);
	if (_finish == _endofstorage)
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}

	iterator it = _finish - 1;//类似最后一个位置的下标
	while (it >= pos)
	{
		*(it + 1) = *it;
		--it;
	}
	*pos = val;

	++_finish;
}

想一想如果传参是void insert(size_t pos, const T& val),在头插的时候就会出现问题,pos = 0,那么it 是size_t 是不会等于-1的就会出错,但是这里用了iterator就不会出现这样的问题,因为pos是迭代器,是一个指针,指针是不会为0的。

但此时代码还存在问题:

v2.insert(v2.begin() + 2, 5.11);
print_vector(v2);

v2.insert(v2.begin() + 2, 5.11);
print_vector(v2);

v2.insert(v2.begin() + 2, 5.11);
print_vector(v2);

v2.insert(v2.begin() + 2, 5.11);
print_vector(v2);

当我多次重复插入

运行代码:

这是为什么,怎么出现了这样的表达式?

原因因为扩容的问题:原来的空间因为扩容已经被释放,pos所处的内存位置还是旧空间上,但是由于被释放,成为了一个野指针。---> 这就是迭代器失效,pos失效,pos所指向的空间已经释放,所以得让pos指向新位置。

所以如果扩容了要更新pos --->:

先算好pos所处的相对位置,即算出他与首位的差值,从而便于修改。

void insert(iterator pos, const T& val)
{
	assert(pos >= _start);
	assert(pos <= _finish);
	if (_finish == _endofstorage)
	{
		size_t len = pos - _start;//算pos所处的相对位置,便于扩容时,pos一并跟着修改
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _start + len;
	}

	iterator it = _finish - 1;//最后一个位置的下标
	while (it >= pos)
	{
		*(it + 1) = *it;
		--it;
	}
	*pos = val;

	++_finish;
}

输出结果正确:

因而push_back()还可以修改为:


		void push_back(const T& val)
		{
			insert(end(), val);
		}

删除某个位置erase()

挪动数据覆盖的问题,将it置于需删除数据的下一个位置,依次++it,直到最后一个数移动完毕

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

	--_finish;
}

popback()函数又可以复用这个函数

		void pop_back()
		{
			erase(--end()); //尾删
		}

指定大小并且resize()

	void resize(size_t n,const T& val = T())
	{

	}

resize()需要给一个缺省值,不能给0,因为val可以是各种类型,因此可以用上匿名对象T(),无参匿名对象。如果T不是自定义类型,而是内置类型,内置类型没有构造函数,但是现在有了,因为c++ 模版出来后,对内置类型升级,添加了构造函数。

如图:

void resize(size_t n,const T& val = T()) //如果容量比我大,我就扩容,容量比我小,我就缩容
{
	if (n > size())
	{
		reserve(n);
		//插入
		while (_finish < _start + n)
		{
			*_finish = val;
			++_finish;
		}

	}
	else
	{
		//删除
		_finish = _start + n;//相当于只保留n个数据
	}
}

测试代码:

void test_vector2()
{

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

	v1.resize(10);
	print_vector(v1);
}

运行结果:

拷贝构造vector(const vector<T>& v)

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

赋值vector::operator=、交换swap()

具体可以看我的string章节的内容怎么用现代写法来写赋值

//赋值 v1 = v3 现代写法,所有深拷贝的类都可以用这个写法
vector<T>& operator=(vector<T> v) //v = v3,注意不要写成引用了,会改变v3
{
	swap(v);
	return *this;
}

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

迭代器区间构造:template <class InputIterator>

vector (InputIterator first, InputIterator last,                 const allocator_type& alloc = allocator_type());


		//迭代器区间构造,容器一般都会支持一个迭代器区间
		template <class InputIterator>
		//类模版的成员函数可以是函数模版
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
  1. 类模板与成员函数模板

    • 类模板(如 vector)允许用通用类型参数定义类,实例化时指定具体类型(如 vector<int>)。

    • 成员函数模板指类模板中的成员函数自身也可以是模板,拥有独立于类的模板参数。此处构造函数使用 InputIterator 作为模板参数,允许接受任意迭代器类型。

  2. 构造函数分析

    • template <class InputIterator> vector(InputIterator first, InputIterator last) 是一个模板构造函数。

    • 它接受两个迭代器 first 和 last,遍历并将元素添加到容器中(通过 push_back)。

    • 该构造函数不依赖类模板的元素类型 T,只要迭代器解引用后的类型可转换为 T,就能构造 vector<T>

vector (size_type n, const value_type& val = value_type())

当我们屏蔽掉上面的第一个构造函数,下面的函数编译通过,这是为什么?因为他可以匹配这两个函数,编辑器也选择了第一个函数,后面的类型不同就不会匹配第一个函数

解决办法通过查看源代码,

写一个重载版本:

c++11支持的用法:


initializer_list,支持迭代器,本质是可认为x是一个常量数组,其中有两个指针,分别指向开始begin()和结束end()

看看底层:

如图:

因此为了支持vector<int> v1 = {1,2,3,4,5,6,7,8,9},我们需要再写一个

initializer_list 的构造函数

//vector<int> v1 = { 1,2,3,4,5,6,7,8,9 };
vector(initializer_list<T> il)
{
	reserve(il.size());
	for (auto& e : il)
	{
		push_back(e);
	} 
}

c++11也支持去掉括号的直接构造(有点融合Python):

修复扩容的bug

实际上在扩容上有bug,如图:

当我在插入string时,多插入几个后程序出现崩溃

调试代码,确认好像问题出现在析构上,但是实际上析构不会出现问题

实际上问题出现在memcpy(tmp , _start , old_size * sizeof(T))上,

请清楚memcpy是如何拷贝的:

memcpy只把数据拷贝下来了,但是没有拷贝到指向的空间,我们期望的是拷贝到新开的空间,释放上面的_start空间就不会有影响。如何解决?

在C++中,memcpy(void*)函数按字节复制内存,而不会调用对象的拷贝构造函数或赋值运算符。当类型T需要深拷贝时(例如管理动态内存、文件句柄等资源),直接使用memcpy会导致以下问题:

  1. 浅拷贝问题
    memcpy会直接复制对象的二进制内容。如果T包含指针或资源句柄,新旧对象的指针将指向同一块内存。当旧内存被释放(delete[] _start)时,新对象中的指针会变成悬垂指针,后续访问将引发未定义行为(如崩溃、数据损坏)。

  2. 绕过对象的语义
    如果T的拷贝构造函数或赋值运算符包含关键逻辑(如引用计数、资源分配),memcpy会绕过这些逻辑,导致资源泄漏或状态不一致。

  3. 析构函数重复释放
    旧对象被销毁时,其析构函数可能会释放资源(如delete指针)。由于新对象的指针与原对象指向同一资源,当新对象最终销毁时,会再次释放同一资源,导致双重释放错误。

正确做法:使用循环逐个拷贝

通过循环tmp[i] = _start[i],实际调用的是T的赋值运算符(或拷贝构造函数,取决于实现)。这确保了:

  • 每个元素的深拷贝逻辑(如动态内存复制)被正确执行。

  • 对象的生命周期管理(构造/析构)符合C++规则。

示例说明

假设Tstd::string

  • memcpy:复制后,新旧string的指针指向同一内存。旧内存释放后,新string成为悬垂指针。

  • 循环赋值:调用std::string::operator=,执行深拷贝,新旧string独立管理各自的字符数组。

结论

memcpy仅适用于平凡可复制类型(如基本类型、结构体且无资源管理)。对于需要深拷贝或非平凡类型的对象,必须通过循环逐个拷贝,确保语义正确性和资源安全性。

修改后代码,使用赋值的办法:


		void reserve(size_t n)
		{
			if (n > capacity())
			{
				T* tmp = new T[n];
				size_t old_size = size();
				//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 = tmp + old_size;
				_endofstorage = tmp + n;
			}
		}

insert()导致迭代器失效

迭代器失效,扩容后迭代器还指向旧空间(c++貌似已经修复了这个问题,但是这里还是讲一下不能实现的原因),实际上我们的vector对象已经有了新空间:

可以加引用,但是传值会使用其他办法,所以我们不使用引用。而且临时对象具有常性,不能使用引用。库里也没有解决insert失效,因为这里本来就不能使用insert,我们需要在外面重新更新。

重新更新:

erase()会不会导致迭代器失效?会,不能使用迭代器

    
	vector<int>::iterator it = v1.begin();
    //删除偶数
	while (it != v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);//会不会导致迭代器失效
		}

		++it;
	}
	print_vector(v1);
	cout << endl;
	cout << *it << endl;

第一种:

输出:

输入这样的测试代码

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

最后出现这样的报错,程序崩溃:

这都是为什么呢? 

第一种:erase中有挪用数据后++,这里的循环也有++,因此会跳过某些数,因此4没被删掉。

第二种:因为插入的个数是偶数,删除4之后,end()指向空,it又往后++,就会一直错开,错过判断条件。

在vs下使用erase()之后就不能再使用迭代器。linux可以

  erase()更新:查看文档:erase()会返回删除元素的下一个元素的迭代器。

使用重新更新的方法:

更新后代码:


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

			--_finish;
			return pos;
		}

结语:

       随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。

       在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。         你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值