【C++】简化源码——vector的模拟实现

一、前言

本篇的目的很简单,只有一个:模拟实现vector

如何去模拟实现?我们可以看看vector的源码,我们可以抽离出主体框架:

template <class T, class Alloc = alloc>
class vector {
     typedef T value_type;
     typedef value_type* iterator;
     typedef const value_type* const_iterator;
protected:
    iterator start;
    iterator finish;
    iterator end_of_storage;
}

这本质上与T*a,size_t size,size_t capacity是类似的:

image-20221125100737422

对于size = _finish - _start

对于capacity = _endofstorage-_start

有了这些作为铺垫,我们对于vector的模拟实现大概有了一个基本的框架,话不多说,直接进入主题👇


二、无参构造&析构

对于这两个都是我们熟悉的老朋友了

  • 无参构造

初始化全设置为空:

vector()
    :_start(nullptr)
    , _finish(nullptr)
    , _endofstorage(nullptr)
{}
  • 析构
~vector()
{
    delete[] _start;
    _start = _finish = _endofstorage = nullptr;
}

三、基础接口

1.empty和clear

empty

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

clear

void clear()
{
    _finish = _start;//这里可不是置为nullptr哦
}

2.size和capacity

size

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

capacity

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

3.[]和iterator

[]

提供const版本和非const版本:

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

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

iterator

同理普通迭代器和const迭代器版本,同理,范围for循环此时也是可以实现的:

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

四、resize和reserve

这两个接口需要单独拎出来,这是因为后面的插入等相关操作需要用到,所以我们先来看看这两个接口,同时这里有一些问题值得我们去注意:

resize

n个数据去初始化,这个n是多大,会造成什么影响?我们需要进行分类讨论:

image-20221126223553778

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

resize的参数初始化值为T类型的构造,这里可不能直接初始化为0,要是T是自定义类型呢?是vector呢?所以这里如果T是vector的化调用的就是vector的构造函数。另外,这里还需要注意的一点是:构造vector的时候是匿名对象,匿名对象具有常性,不可修改所以要加上const修饰

所以,我们自然而然可以知道,对于内置类型比如int,都是有构造函数的:

image-20221126225324427

reserve

reserve最大的问题就是深拷贝!开辟新空间进行赋值的时候如果直接使用memcpy是浅拷贝

void reserve(size_t n)
{
    if (n > capacity())
    {
        T* tmp = new T[n];
        //size()需要先保存起来,后面_start会发生改变
		size_t sz = size();
        //为空不需要拷贝了
        if (_start)
        {
            for (size_t i = 0; i < sz; i++)
            {
                tmp[i] = _start[i];
            }
            delete[] _start;
            //memcpy(tmp, _start, sizeof(T) * size());//浅拷贝
            //delete[] _start;
        }
        _start = tmp;
        _finish = _start+sz;
        _endofstorage = _start + n;
    }
}
  • size()需要先用sz保存

为啥?如果没有保存:

_start = tmp;
_finish = _start+size();
_endofstorge = _start+n;

不要忘了:size()=_finish-_start, 而_start = tmp会更新_start;根本就不是原来的size()了

  • 使用memcpy问题

memcpy拷贝数据,拿vector<vector>作为例子,其中vector仍然是浅拷贝的,对于自定义类型出现问题

vector<vector<int>> vv;
vector<int> v(4, 1);
//复用push_back尾插
vv.push_back(v);
vv.push_back(v);
vv.push_back(v);
vv.push_back(v);
//需要扩容成2倍
vv.push_back(v);
for (size_t i = 0; i < vv.size(); i++)
{
for (size_t j = 0; j < vv[i].size(); j++)
{
  cout << vv[i][j] << " ";
}
cout << endl;
}

image-20221127001111216


五、尾插尾删

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


void pop_back()
{
    assert(_finish > _start);
    --_finish;
}

六、其他构造

这里需要复用前面的一些接口,所以放在这个地方

  • 迭代器区间构造

这里复用了push_back,而且写成了模板

template <class InputIterator>
    //模板可以使用其他迭代器区间
vector(InputIterator first, InputIterator last)
    :_start(nullptr)
	, _finish(nullptr)
	, _endofstorage(nullptr)
    {
        while (first != last)
        {
            push_back(*first);//int不能解引用
            ++first;
        }
    }

类模板的成员函数可以是函数模板,使之可以是任意类型的迭代器区间,包括了自身的迭代器区间构造

另外,初始化列表全部初始化为nullptr,没有初始化就是随机值,出现野指针

  • 拷贝构造

初始化列表全都要初始化为nullptr,否则就是随机值

//写法1
vector(const vector<T>& v)
    :_start(nullptr)
	,_finish(nullptr)
	,_endofstorage(nullptr)
    {
        reserve(v.capacity());
        for (const auto& e : v)
        {
            push_back(e);
        }
    }

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

vector(const vector<T>& v)
    :_start(nullptr)
    , _finish(nullptr)
	, _endofstorage(nullptr)
    {
        vector<T> tmp(v.begin(), v.end());
        swap(tmp);
    }
  • 赋值重载

赋值重载需要复用拷贝构造

	//缺陷:自己拷贝自己
//v1(v2)
vector<T>& operator=(vector<T> v)
{
    swap(v);
    return *this;
}

这种写法就是有一个小问题:如果是自己拷贝自己呢?加个判断?没用,因为此时已经传值传参过来了,加个判断没啥意义了。但是这个问题不大,我们允许存在,平时自己也很少自己赋值自己。

另外,这里是传值调用,有人会说了:传引用也可以啊,此时如果是引用的话,v2赋值给v1,v1不是v2的拷贝,直接把v2换成了v1,v1换给了v2,v2本身已经发生变化了,这不是赋值了。


七、迭代器失效

1.insert

insert这个太熟悉了,废话不多说直接上手代码:

//迭代器失效:扩容引起野指针问题
void insert(iterator pos, const T& val)
{
    assert(pos >= _start);
    assert(pos <= _finish);
    if (_finish == _endofstorage)
    {
        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newCapacity);
    }
    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        --end;
    }
    *pos = val;
    ++_finish;
}

测试代码:

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

		for (size_t i = 0; i < v.size(); i++)
		{
			cout << v[i] << " ";
		}
		cout << endl;
		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			v.insert(it, 30);
		}
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
}

image-20221127102831809

这是因为扩容导致pos失效了:

image-20221127103607613

insert过程中发生扩容,导致it指向的空间实际上已经被释放,it指向已被释放的空间是野指针,造成了迭代器失效

所以,我们应该去更新pos,算出pos刚开始的相对位置,然后再去进行更新即可解决问题。但是此时外面调用insert的it仍然是失效的,因为是传值调用,形参改变不影响实参,可以通过返回值接收解决问题。(如果是传引用的话,只能传变量,而临时对象具有常性,不能调用,存在很多问题),所以直接用返回值解决。

iterator insert(iterator pos, const T& val)
{
    assert(pos >= _start);
	assert(pos <= _finish);
    if (_finish == _endofstorage)
    {
        //扩容会导致pos迭代器失效,需要更新
        size_t len = pos - _start;
        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newCapacity);
        pos = _start + len;
    }
    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        --end;
    }
    *pos = val;
    ++_finish;
    return pos;
}

测试代码:

void Test3()
{
    vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (size_t i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
    v.insert(v.begin(), 0);
    vector<int>::iterator it = find(v.begin(), v.end(), 3);
    if (it != v.end())
    {
        v.insert(it, 30);
    }
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}

image-20221127110313361

2.erase

挪动数据进行覆盖即可

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

erase的pos也可能会导致pos失效,测试代码:

void Test6()
	{
		//删除所有偶数
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			if (*it % 2 == 0)
			{
				v.erase(it);
			}
			++it;
		}
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}

测试发现:

1,2,3,4的时候发生崩溃

1,2,2,3,5结果只删了一个2

1,2,3,4,5结果是正常的

image-20221127140628122

上述代码在VS下,当erase(it)之后,it指向的位置发生改变,然后在++it的话,会出现问题,出现一些错误,造成迭代器失效。

我们最好统一认为失效了。

正确的erase:

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

测试代码:

void Test6()
	{
		//删除所有偶数
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		vector<int>::iterator 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;
	}

image-20221127121509374

对于insert和erase存在迭代器失效的问题,当迭代器失效而来,我们就不要再去访问pos的位置了,要更新pos的位置,可通过返回值接收进行访问,


八、memcpy问题

如果拷贝的是内置类型的元素,memcpy即高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝,指向同一块空间,假设我们仍然在reserve接口中使用memcpy进行拷贝:

我们以vector类为例子:

void Test10()
{
    vector<string> v;
    v.push_back("11111111111111111111");
    v.push_back("22222222222222222222");
    v.push_back("33333333333333333333");
    v.push_back("44444444444444444444");
    v.push_back("55555555555555555555");
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}

image-20221127143935504

image-20221127145226373

所以我们要调用自己的拷贝,一个一个进行深拷贝。


九、vector.h

#define _CRT_SECURE_NO_WARNINGS

#pragma once

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

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

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

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

		/*vector(const vector<T>& v)
			:_start(nullptr)
			,_finish(nullptr)
			,_endofstorage(nullptr)
		{
			reserve(v.capacity());
			for (const auto& e : v)
			{
				push_back(e);
			}
		}*/


		//vector<int> v1(10, 5);
		//vector<char> v2(10, 'A');
		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}
		//改成int或强转
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			reserve(n);
			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);//int不能解引用
				++first;
			}
		}
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);
		}

		//缺陷:自己拷贝自己
		vector<T>& operator=(vector<T> v)
		{

			swap(v);
			return *this;
		}
		~vector()
		{
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				T* tmp = new T[n];
				size_t sz = size();
				//为空不需要拷贝了
				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
					//memcpy(tmp, _start, sizeof(T) * size());//浅拷贝
					//delete[] _start;
				}
				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}

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

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

		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
			}

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(_finish > _start);
			--_finish;
		}

		//迭代器失效:野指针问题
		/*void insert(iterator pos, const T& val)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			if (_finish == _endofstorge)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = val;
			++_finish;
		}*/

		iterator insert(iterator pos, const T& val)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _endofstorage)
			{
				//扩容会导致pos迭代器失效,需要更新
				size_t len = pos - _start;
				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = val;
			++_finish;

			return pos;
		}

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

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

		void clear()
		{
			_finish = _start;
		}
	public:
		iterator _start;
		iterator _finish;
		iterator _endofstorage;
	};


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

		cout << v.size() << endl;
		cout << v.capacity() << endl;

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

	void Test2()
	{
		vector<int> v;
		v.resize(10, -1);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		v.resize(5);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
		v.pop_back();
		v.pop_back();
		v.pop_back();
		v.pop_back();
		v.pop_back();
		v.pop_back();
	}
	void Test3()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);

		for (size_t i = 0; i < v.size(); i++)
		{
			cout << v[i] << " ";
		}
		cout << endl;
		v.insert(v.end(), 0);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			v.insert(it, 30);
		}
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void Test4()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			//传值
			v.insert(it, 30);
		}
		//insert以后it不能使用,可能迭代器失效(野指针)
		//(*it)++;

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void Test5()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		vector<int>::iterator it = find(v.begin(), v.end(), 3);
		if (it != v.end())
		{
			v.erase(it);
		}
		cout << *it << endl;
		//	(*it)++;
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}


	void Test6()
	{
		//删除所有偶数
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		vector<int>::iterator 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;
	}

	void Test7()
	{
		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> v1(v);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int> v2;
		v2.push_back(10);
		v2.push_back(20);
		v2.push_back(30);
		v1 = v2;
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

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


	void Test8()
	{
		string str("hello world");

		vector<int> v(str.begin(), str.end());
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		/*vector<int> v1(v.begin(), v.end());*/
		vector<int> v1(10, 5);
		//vector<char> v2(10, 'A');
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}



	class Solution {
	public:
		vector<vector<int>> generate(int numRows) {
			vector<vector<int>> vv;
			vv.resize(numRows);
			for (size_t i = 0; i < vv.size(); i++)
			{
				vv[i].resize(i + 1, 0);
				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;
		}
	};

	void Test9()
	{
		vector<vector<int>> vvRet = Solution().generate(5);

		for (size_t i = 0; i < vvRet.size(); i++)
		{
			for (size_t j = 0; j < vvRet[i].size(); j++)
			{
				cout << vvRet[i][j] << " ";
			}
			cout << endl;
		}
		/*vector<vector<int>> vv;
		vector<int> v(10, 1);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);
		vv.push_back(v);

		for (size_t i = 0; i < vv.size(); i++)
		{
			for (size_t j = 0; j < vv[i].size(); j++)
			{
				cout << vv[i][j] << " ";
			}
			cout << endl;
		}*/
		cout << endl;
	}

	void Test10()
	{
		vector<string> v;
		v.push_back("11111111111111111111");
		v.push_back("22222222222222222222");
		v.push_back("33333333333333333333");
		v.push_back("44444444444444444444");
		v.push_back("55555555555555555555");

		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平凡的人1

佬的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值