[C++] STL—vector simulation implementation, common constructors, iterators, operator overloading, expansion functions, additions, deletions, checks and modifications

1. Simulate the implementation of vector

vector usage article

insert image description here

1.1 Constructor

insert image description here

destructor

insert image description here

  In C++, a vector is a dynamic array container that automatically resizes as needed. The vector class provides several different constructors to create and initialize vector objects.

  (1) Default constructor: vector<type> v; creates an empty vector object v, where type is the data type of the elements in vector. This constructor will create a vector with an initial size of 0.

  (2) Constructor with initial size: vector<type> v(n); Creates a vector object v of size n and initializes all elements to default values. For example, if the type is int, all elements will be initialized to 0.

  (3) Constructor with initial value: vector<type> v(n, initial value); Creates a vector object v of size n and initializes all elements to the given initial value. For example, if the type is int and the initial value is 5, all elements will be initialized to 5.

  (4) Copy constructor: vector<type> v(v2); Creates a new vector object v that contains the same elements as another vector object v2. This constructor will copy all elements in v2.

  (5) Use the constructor of the iterator: vector<type> v(begin, end); Create a new vector object v, which contains all elements from the iterator begin to the iterator end. This constructor will copy the elements.

namespace vec
{
    
    
	//类模板
	template<class T>
	class vector
	{
    
    
	public:
		//带有初始值的构造函数
		vector(size_t n, const T& val = T())
		{
    
    
			resize(n, val);
		}
		
		//带有初始值的构造函数
		vector(int n, const T& val = T())
		{
    
    
			resize(n, val);
		}

		//使用迭代器的构造函数
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
    
    
			while (first != last)
			{
    
    
				push_back(*first);
				++first;
			}
		}

		//空构造函数
		vector()
		{
    
     }

		构造函数
		//vector()
		//	:_start(nullptr)
		//	,_finish(nullptr)
		//	,_end_of_storage(nullptr)
		//{}

		//深拷贝实现拷贝构造
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
    
    
			_start = new T[v.capacity()];
			//memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t i = 0; i < v.size(); i++)
			{
    
    
				_start[i] = v._start[i];
			}

			_finish = _start + v.size();
			_end_of_storage = _start + v.capacity();
		}

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

	private:
		//成员变量给缺省值
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};
}

1.2 Iterators

insert image description here
insert image description here

  Similar to the use of string iterators, the begin function returns an iterator pointing to the beginning of the string, and the end function returns an iterator pointing to the end of the string . This way, the string can be traversed using standard iterator operations, such as using a loop to iterate through each character.

  For ordinary vector types, the compiler calls the iterators of the above two types of iterators, indicating that the container of this type can be read and written; for vectors of const type, the compiler calls the following two iterators of types const_iterator, Indicates only writable permission for this type of container.

  In this way, by calling the begin() and end() functions, you can get the iterators of the start position and end position of the vector container, and then use the iterator to traverse and manipulate the elements in the container.

//T类指针来实现迭代器
typedef T* iterator;
typedef const T* const_iterator;

//迭代器
iterator begin()
{
    
    
	return _start;
}

iterator end()
{
    
    
	return _finish;
}

//const修饰的迭代器
const_iterator begin() const
{
    
    
	return _start;
}

const_iterator end() const
{
    
    
	return _finish;
}

1.3 Operator overloading


assignment operator overloading

  The assignment operator operator= is overloaded to accept a vector object as an argument and return a reference to the current object. In the overload implementation, first create a temporary vector object v, and copy the incoming vector object to v. Then, call the swap function to exchange the member variables of the current object and the temporary object. Finally, a reference to the current object is returned to support continuous assignment operations.

  In this way, efficient assignment operations can be achieved, element-by-element copying is avoided, and performance is improved. At the same time, using the swap function to exchange can ensure that resource leaks will not be caused when an exception occurs.

insert image description here

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)
{
    
    
	swap(v);

	return *this;
}

Overloading operator[]

insert image description here

  For the normal version, we overload the operator[] operator, returning a readable and writable reference. It accepts one parameter pos, indicating the position of the element to be accessed. Inside the function, assert through the assert function to ensure that pos is within the valid range, that is, smaller than the size of the vector. Then, return a reference to _start[pos] to read and write the element at the specified position.

  For the vector of const type, we add const to the previous version of the operator[] operator to modify and return a read-only reference. It also accepts a parameter pos, and asserts through the assert function to ensure that pos is within the valid range. Then, return a const reference to _start[pos] for read-only access to the element at the specified position.

  By overloading the operator[] operator, you can access the elements in the vector container through subscripts just like using an array. Also, by overloading the constant version of operator[], read-only access is also possible on constant objects.

//重载operator[] 可读可写
T& operator[](size_t pos)
{
    
    
	assert(pos < size());

	return _start[pos];
}

//重载operator[] 只读不可写
const T& operator[](size_t pos) const
{
    
     
	assert(pos < size());

	return _start[pos];
}

1.4 Expansion function

reserve and resize

insert image description here

insert image description here

  The reserve function is used to resize the vector object to be at least n. If n is greater than the current capacity, capacity expansion is required. Inside the function, first obtain the size of the current vector, and then create a temporary pointer tmp, pointing to a new array of size n. If the current vector is not empty, copy the original elements to the new array one by one.

  Note that if the element type is a custom type, a shallow copy problem may occur, and the memcpy function cannot be used for memory copying.

  The resize function is used to adjust the size of the vector object to n, and fill the specified element value val when needed. If n is less than the current size, move the _finish pointer to a new location, ie truncate the vector. If n is greater than the current size, call the reserve function to perform capacity expansion. Then, the new element value is copied into the vector by looping until the _finish pointer points to the new location. This implements the function of resizing the vector to n and filling the specified element values ​​when needed.

  Through these two functions, the capacity and size of the vector container can be adjusted, and elements can be copied and filled during expansion and resizing. In this way, the memory space and the number of elements of the vector container can be flexibly managed.

//扩容函数capacity
void reserve(size_t n)
{
    
    
	if (n > capacity())
	{
    
    
		size_t sz = size();
		T* tmp = new T[n];
		if (_start)
		{
    
    
			//如果是自定义类型,假如string,则会出现浅拷贝
			//memcpy(tmp, _start, sizeof(T) * sz);
			for (size_t i = 0; i < sz; i++)
			{
    
    
				tmp[i] = _start[i];
			}

			delete[] _start;
		}

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

//扩容size
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;
		}
	}
}

capacity and size

  The size range of capacity is: _end_of_storage - _start

  The size range of size is: _finish - _start

  It should be noted that the size of the vector is not necessarily equal to the capacity, and the size can be less than or equal to the capacity. When adding elements to the vector, the size will increase; when removing elements from the vector, the size will decrease. When the size exceeds the capacity, the vector will automatically reallocate the memory, usually allocate a larger memory space, copy the original elements to the new memory space, and release the original memory space.

insert image description here

insert image description here

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

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

1.5 Add, delete, check and modify

push_back

  Implementation of the push_back function, used to add an element at the end of the vector.

insert image description here

//尾插
void push_back(const T& v)
{
    
    
	if (_finish == _end_of_storage)
	{
    
    
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
	}

	*_finish = v;
	++_finish;
	//insert(end(),x)
}

insert

  The implementation of the insert function, which is used to insert an element at pos in the vector.

insert image description here

//插入
iterator insert(iterator pos, const T& x)
{
    
    
	assert(pos >= _start && pos <= _finish);

	//判断是否扩容
	if (_finish == _end_of_storage)
	{
    
    
		size_t len = pos - _start;

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

		//解决pos迭代器失效问题
		pos = _start + len;
	}

	iterator end = _finish - 1;
	while (end >= pos)
	{
    
    
		*(end + 1) = *end;
		end--;
	}

	*pos = x;
	_finish++;

	return pos;
}

erase

  The implementation of the erase function is used to delete the specified element at the pos position of the vector.

insert image description here

//删除
iterator erase(iterator pos)
{
    
    
	assert(pos >= _start && pos <= _finish);

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

	--_finish;

	return pos;
}

fully realized

#pragma once

#include<assert.h>

namespace vec
{
    
    
	//类模板
	template<class T>
	class vector
	{
    
    
	public:
		//T类指针来实现迭代器
		typedef T* iterator;
		typedef const T* const_iterator;

		//迭代器
		iterator begin()
		{
    
    
			return _start;
		}

		iterator end()
		{
    
    
			return _finish;
		}

		//const修饰的迭代器
		const_iterator begin() const
		{
    
    
			return _start;
		}

		const_iterator end() const
		{
    
    
			return _finish;
		}

		//构造函数,将空间填充为val对象
		vector(size_t n, const T& val = T())
		{
    
    
			resize(n, val);
		}

		vector(int n, const T& val = T())
		{
    
    
			resize(n, val);
		}

		//构造函数,迭代区间进行构造
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
    
    
			while (first != last)
			{
    
    
				push_back(*first);
				++first;
			}
		}

		//空构造函数
		vector()
		{
    
     }

		构造函数
		//vector()
		//	:_start(nullptr)
		//	,_finish(nullptr)
		//	,_end_of_storage(nullptr)
		//{}

		//深拷贝实现拷贝构造
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
    
    
			_start = new T[v.capacity()];
			//memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t i = 0; i < v.size(); i++)
			{
    
    
				_start[i] = v._start[i];
			}

			_finish = _start + v.size();
			_end_of_storage = _start + v.capacity();
		}

		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)
		{
    
    
			swap(v);

			return *this;
		}

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

		//扩容函数capacity
		void reserve(size_t n)
		{
    
    
			if (n > capacity())
			{
    
    
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
    
    
					//如果是自定义类型,如果是string,则会出现浅拷贝
					//memcpy(tmp, _start, sizeof(T) * sz);
					for (size_t i = 0; i < sz; i++)
					{
    
    
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

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

		//扩容size
		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;
				}
			}
		}

		//尾插
		void push_back(const T& v)
		{
    
    
			if (_finish == _end_of_storage)
			{
    
    
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}

			*_finish = v;
			++_finish;
			//insert(end(),x)
		}

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

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

		//重载operator[] 可读可写
		T& operator[](size_t pos)
		{
    
    
			assert(pos < size());

			return _start[pos];
		}

		//重载operator[] 只读不可写
		const T& operator[](size_t pos) const
		{
    
     
			assert(pos < size());

			return _start[pos];
		}

		//插入
		iterator insert(iterator pos, const T& x)
		{
    
    
			assert(pos >= _start && pos <= _finish);

			//判断是否扩容
			if (_finish == _end_of_storage)
			{
    
    
				size_t len = pos - _start;

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

				//解决pos迭代器失效问题
				pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
    
    
				*(end + 1) = *end;
				end--;
			}

			*pos = x;
			_finish++;

			return pos;
		}

		//删除
		iterator erase(iterator pos)
		{
    
    
			assert(pos >= _start && pos <= _finish);

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

			--_finish;

			return pos;
		}

	private:
		//成员变量给缺省值
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};

	//打印
	template<class T>
	void print(const T& v)
	{
    
    
		for (auto e : v)
		{
    
    
			cout << e << " ";
		}
		cout << endl;
	}
}


test code

#define _CRT_SECURE_NO_WARNINGS 1

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

#include"vector.h"

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

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

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

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

	vec::print(v1);
}

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

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

	v1.insert(v1.begin(), 10);

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

	vec::vector<int>::iterator p = v1.begin() + 3;
	//insert迭代器可能会失效
	//insert建议不要使用这个形参迭代器
	v1.insert(p, 100);

	*p += 10;

	vec::print(v1);
}

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

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

	//v1.erase(v1.begin());
	auto it = v1.begin()+4;
	v1.erase(it);

	//erase以后,迭代器失效了,不能访问it指向的空间
	//因为vs会对其进行强制检查,访问会报错
	cout << *it << endl;
	++it;
	cout << *it << endl;

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

void test_vector4()
{
    
    
	vec::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	for (auto e : v1)
	{
    
    
		cout << e << " ";
	}
	cout << endl;

	vec::vector<int> v2(v1);
	for (auto e : v1)
	{
    
    
		cout << e << " ";
	}
	cout << endl;

	vec::vector<int> v3;
	v3 = v1;
	vec::print(v3);
}

void test_vector5()
{
    
    
	vector<string> v1;
	v1.push_back("11111");
	v1.push_back("22222");
	v1.push_back("33333");
	v1.push_back("44444");
	v1.push_back("55555");

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

	vector<string> v2(v1);
	for (auto& e : v2)
	{
    
    
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
    
    
	//test_vector1();
	//test_vector2();
	//test_vector3();
	//test_vector4();
	test_vector5();
	return 0;
}

Guess you like

Origin blog.csdn.net/Crocodile1006/article/details/132030645