C++万字总结(中篇)

菜狗程序员 C++ 万字总结,从入门到入土(中篇)

STL

vector

模拟实现

#include <iostream>

namespace Schuyler
{
   
	// 因为 vector 容器可以存放任意类型,所以要用模板
	template <class T>
	class vector
	{
   
	public:
		// 用迭代器包装任意类型的指针
		typedef T* iterator;
		typedef const T* const_iterator;
		// begin 返回空间起始地址
		iterator begin()
		{
   
			return _start;
		}
		// end 返回最后一个有效数据的下个空间的地址
		iterator end()
		{
   
			return _finish;
		}
		// const 对象调用,只有读权限,不能写
		const_iterator begin() const
		{
   
			return _start;
		}
		const_iterator end() const
		{
   
			return _finish;
		}
		// 扩容
		void reserve(int n)
		{
   
			if (capacity() < n)
			{
   
				int sz = size();
				// 开辟新空间
				T* p = new T[n];
				if (_start)
				{
   
					// 旧空间数据拷贝到新空间
					for (int i = 0; i < sz;i++)
					{
   
						p[i] = _start[i];
					}					
				}
				// 释放旧空间
				delete[] _start;
				// 指针指向新空间
				_start = p;
				_finish = p + sz;
				_endOfStorage = _start + n;
			}
		}
		// 调整 size
		void resize(int n, T val = T())
		{
   
			// 要求调整的 size 小于 有效数据个数,则直接移动 _finish
			if (n < size())
			{
   
				_finish = _start + n;
			}
			else
			{
   
				// 要求的 size 大于 容量,则另外开辟一块空间
				if (n > capacity())
				{
   
					reserve(n);
				}
				// 从数据末尾存放新的数据 val
				while (_finish < _start + n)
				{
   
					*_finish = val;
					++_finish;
				}
			}
		}
		// 数据尾插就是往 _finish 处添数据
		void push_back(const T& val)
		{
   
			if (capacity() == size())
			{
   
				const int newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
			}
			*_finish = val;
			++_finish;
		}
		// 尾删
		void pop_back()
		{
   
			if (empty())
				throw new _exception{
    1, "容器为空" };

			--_finish;
		}
		// 任意位置插入
		void insert(iterator pos, const T& val)
		{
   
			// 判断是否需要扩容
			if (_finish == _endOfStorage)
			{
   
				// 计算 pos 离起始位置的距离,方便扩容后找到新空间的 pos
				int len = pos - _start;
				
				int 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;
		}
		// 删除任意位置元素
		iterator erase(iterator pos)
		{
   
			iterator it = pos + 1;
			while (it != _finish)
			{
   
				*(it - 1) = *it;
				++it;
			}
			--_finish;
			return pos;
		}
		
		// 构造函数给三个成员变量赋初值
		vector()
		{
   
			_start = nullptr;
			_finish = nullptr;
			_endOfStorage = nullptr;
		}

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

		// 拷贝构造
		vector(const vector<T>& v)
		{
   
			_start = new T[v.capacity()];
			for (int i = 0; i < v.size(); i++)
			{
   
				_start[i] = v._start[i];
			}
			_finish = _start + v.size();
			_endOfStorage = _start + v.capacity();
		}
	private:
		void swap(vector<T>& v)
		{
   
			_start = v._start;
			_finish = v._finish;
			_endOfStorage = v._endOfStorage;
		}
	public:
		// 赋值运算符
		vector<T>& operator=(vector<T> v)
		{
   
			swap(v);
			
			return *this;
		}
		// 析构函数
		~vector()
		{
   
			if (_start)
			{
   
				delete[] _start;
			}
			_start = _finish = _endOfStorage = nullptr;
		}
		// vector 索引
		T& operator[](int i)
		{
   
			if (i >= size())
				throw new _exception{
    0, "索引错误" };

			return _start[i];
		}
		
		const T& operator[](int i)const
		{
   
			if (i >= size())
				throw new _exception{
    0, "索引错误" };

			return _start[i];
		}
		
		
	private:
		// 指向数组空间起始位置
		iterator _start;
		// 指向数组空间中有效数据末尾的下一个位置
		iterator _finish;
		// 指向数组空间的末尾
		iterator _endOfStorage;
	public:
		// 有效数据个数
		int size() const
		{
   
			return _finish - _start;
		}
		// 容器空间大小
		int capacity() const
		{
   
			return _endOfStorage - _start;
		}
		// 判断容器是否为空
		bool empty()
		{
   
			return _finish == _start;
		}
	};
}


vector 迭代器失效问题:

引起迭代器失效的情况有两种,

  1. 一种是像 resize、reserve、insert、push_back 这些能改变数据空间的操作,扩容操作会使原先空间销毁,从而产生野指针,因此需要对迭代器重新赋值。
  2. 即使不扩容,只要发生数据挪动,迭代器原先指向的空间可能也会发生变化,从而迭代器失效,比如 erase 操作。

另一种

string

模拟实现

# include <iostream>

namespace Schuyler
{
   
	class string
	{
   
	public:
		// 四个默认成员函数
		// 构造函数
		string(const char* str = "")
		{
   
			if (nullptr == str)
				throw new _exception{
   0,"字符串指针为 nullptr"};
			int size = strlen(str);
			// +1 是为了保留 ‘\0’
			_str = new char[size + 1];
			strcpy(_str, str);
			
			_size = size;
			_capacity = size;
		}
		// 析构函数
		~string()
		{
   
			if (_str != nullptr)
			{
   
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}		
		}
		// 拷贝构造
		string(const string& str)
		{
   
			_str = nullptr;
			_size = _capacity = 0;
			// 开辟一块和 str 一样的空间
			string tmp(str._str);
			// 将新空间和 _str 交换,新空间的字符指针变为 nullptr,tmp 出作用域空间释放
			swap(tmp);
		}
		// 赋值运算符号
		string& operator=(string str)
		{
   
			// 因为 str 传值类型,会拷贝构造一个临时对象,可以借临时对象来赋值,出作用域,临时对象销毁
			swap(str);
			return *this;
		}
		// 对字符串进行索引,const 对象索引返回值不能修改
		const char& operator[](int i) const
		{
   
			if (i < 0)
				throw new _exception{
    1, "字符串索引错误" };
			return _str[i];
		}
		char& operator
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Schuyler Hu

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值