0
点赞
收藏
分享

微信扫一扫

Mybatis sql 控制台格式化

九月的栩 03-12 22:00 阅读 2

注意

实现仿cplus官网的的string类,对部分主要功能实现

实现

文件

#pragma once
#include <string>
#include <assert.h>

namespace myvector
{
	template <class T>
	class vector
	{
	public:

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

		//constructor
			//default
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}
			//fill
		//匿名对象加const引用生命周期延长至变量结束
		vector(size_t n, const T& val = T()) 
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			Reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				PushBack(val);
			}
				
		
		}
		//重载int版,防止调用迭代器区间
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			Reserve(n);
			for (int i = 0; i < n; i++)
			{
				PushBack(val);
			}

		}
			//range
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr) //可以使用默认值,不用初始化列表
		{
			//迭代器必须用不等于,因为list可能后边的指针更小
			while (first != last)
			{
				PushBack(*first);
				first++;
			}
		}
			//copy 实现深拷贝,不然会浅拷贝
		vector(const vector<T>& x)
		{
			//Reserve(x.Capacity());
			_start = new T[x.Capacity()];
			//深拷贝,不能用memcpy,避免T是结构仍浅拷贝
			//memcpy(_start, x._start, sizeof(T) * x.Size());
			for (size_t i = 0; i < x.Size(); i++)
			{
				_start[i] = x._start[i];
			}
			_finish = _start + x.Size();
			_end_of_storage = _start + x.Capacity();
		}

		//add
		void PushBack(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t capacity = Capacity() == 0 ? 4 : Capacity() * 2;
				Reserve(capacity);
			}

			*_finish = x;
			_finish++;
		}

		iterator Insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			if (_finish == _end_of_storage)
			{
				size_t sz = pos - _start;
				//扩容后的迭代器失效问题,更新pos
				Reserve(Capacity() == 0 ? 4 : Capacity() * 2);
				pos = _start + sz;
			}

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

			*pos = x;
			_finish++;

			return pos;
		}

		//de
		void PopBack()
		{
			assert(!Empty());
			_finish--;
		}

		iterator Erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

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

			return pos;
		}

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

		const T& operator[](size_t pos) const
		{
			assert(pos < Size());
			return _start[pos];
		}
		//size capacity
		size_t Size() const
		{
			return _finish - _start;
		}

		bool Empty() const
		{
			return Size() == 0;
		}
		size_t Capacity() const
		{
			return _end_of_storage - _start;
		}

		void Reserve(size_t n)
		{

			if (n > Capacity())
			{
				T* tmp = new T[n];
				size_t size = Size();
				if (_start)
				{
					//memcpy(tmp, _start, Size() * sizeof(T));
					for (size_t i = 0; i < Size(); i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + size;
				_end_of_storage = _start + n;
			}


		}
		//类型()调默认构造,内置类型也可以
		//首先判断设置的大小是否大于当前size,大于就需要设置参数的数据,同时还考虑扩容
		void Resize(size_t n, T x = T())
		{
			if (n > Size())
			{
				if (n > Capacity())
				{
					Reserve(n);
				}

				while (_finish != _start + n)
				{
					*_finish = x;
					_finish++;
				}

			}
			_finish = _start + n;
		}

		//destructor
		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;
	};
}

测试

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include "vector.h"

using namespace myvector;
//void fun(const vector<int>& x)
//{
//	for (auto ch : x)
//	{
//		std::cout << ch << std::endl;
//	}
//}

class Solution {
public:
	vector<vector<int>> generate(int numRows) {
		vector<vector<int>> vv;
		vv.Resize(numRows, vector<int>());
		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;
	}
};

//vector<int> fun2()
//{
//	vector<int> s;
//	return s;
//}
int main()
{
	vector<int> v1;
	v1.PushBack(1);
	v1.PushBack(2);
	v1.PushBack(8);
	v1.PushBack(3);
	v1.PushBack(10);
	v1.PushBack(6);
	v1.PushBack(1);
	v1.PushBack(2);
	v1.PushBack(8);
	v1.PushBack(3);
	v1.PushBack(10);
	v1.PushBack(6);

	/*std::vector<int> v2;
	v2.push_back(1);
	v2.push_back(2);
	v2.push_back(8);
	v2.push_back(3);*/
	//v1.PushBack(6);
	/*vector<int>::iterator pos = std::find(v1.begin(), v1.end(), 2);
	v1.Insert(pos, 3);*/
	/*vector<int>::iterator pos = v1.begin() + 2;
	v1.Erase(pos);
	for (int i = 0; i < v1.Size(); i++)
	{
		std::cout << v1[i] << " ";
	}*/
	/*std::vector<int>::iterator pos = v2.begin() + 2;
	for (int i = 0; i < v2.size(); i++)
	{
		std::cout << v2[i] << " ";
	}
	std::cout << std::endl;*/
	/*fun(v1);*/
	/*v1.PopBack();
	v1.PopBack();
	v1.PopBack();*/
	//v1.Resize(8, 4);
	//vector<int>::iterator pos = std::find(v1.begin(), v1.end(), 5);
	/*if (pos != v1.end())
	{
		pos = v1.Insert(pos, 8);
	}*/
	//vs insert和erase后迭代器都不能再使用,强制检查
	//(*pos)++;
	/*std::vector<int>::iterator it = v2.begin();
	while (it != v2.end())
	{
		if (*it % 2 == 0)
		{
			it = v2.erase(it);
		}
		else
		{
			it++;
		}
	}*/
	/*std::vector<int>::iterator pos1 = std::find(v2.begin(), v2.end(), 2);
	v2.erase(pos1);
	pos1++;*/
	/*vector<int>::iterator it2 = v1.begin();
	while (it2 != v1.end())
	{
		std::cout << *it2 << " ";
		it2++;
	}*/

	/*vector<int> v3(10, 5);
	vector<int>::iterator it2 = v3.begin();
	while (it2 != v3.end())
	{
		std::cout << *it2 << " ";
		it2++;
	}*/
	
	//std::cout << std::endl;
	//int ary[] = { 5,4,3,2,1 };
	//vector<int> v4(ary, ary + 3);
	//排序algorithm头文件的排序
	//template <class RandomAccessIterator>
	// sort(RandomAccessIterator first, RandomAccessIterator last);
	//std::sort(v4.begin(), v4.end());
	/*vector<int>::iterator it3 = v4.begin();
	while (it3 != v4.end())
	{
		std::cout << *it3 << " ";
		it3++;
	}*/
	//降序,要传模板
	//template <class T> struct greater;
	/*std::greater<int> g;
	std::sort(ary, ary + sizeof(ary)/sizeof(ary[0]), g);
	for (auto ch : ary)
	{
		std::cout << ch << " ";
	}*/

	//vector<std::string> v2(3, "111");
	vector<vector<int>> v3 = Solution().generate(5);
	for (size_t i = 0; i < v3.Size(); ++i)
	{
		for (size_t j = 0; j < v3[i].Size(); ++j)
		{
			std::cout << v3[i][j] << " ";
		}
		std::cout << std::endl;
	}

	vector<int> v4;
	v4.Insert(v4.begin(), 4);;

	return 0;
}

注意事项

vector可以存储任意类型的元素,所以用模板,用三个指针,一个记录数组的首地址,finish记录最后一个元素的下一个地址,end_of_storage记录数组范围的地址,类型是模板T类型指针

对于T类型的值给默认值,不能默认给0,有可能是自定义结构,所以需要调用对应的构造函数,内置类型也可以这样构造

拷贝构造不能用memcpy,如果对象涉及资源管理就会浅拷贝,内存泄露或崩溃,所以要用赋值走运算符重载
在这里插入图片描述

赋值运算符重载,避免T是结构体的浅拷贝

Insert中元素的长度在扩容前需要记录,不然会失效

迭代器失效

迭代器的作用是让算法不用关心底层数据结构,实际就是一个指针,或者是对指针封装。比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器对应指针的指向的空间销毁了,使用一块已经被释放的空间,造成的后果就是程序崩溃

1.会引起底层空间改变的操作,都有可能是迭代器失效,如:resize、reserve、insert、assign、pushback等

#include <iostream>
using namespace std;
#include <vector>
int main()
{
 vector<int> v{1,2,3,4,5,6};
 
 auto it = v.begin();
 
 // 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
 // v.resize(100, 8);
 
 // reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变
 // v.reserve(100);
 
 // 插入元素期间,可能会引起扩容,而导致原空间被释放
 // v.insert(v.begin(), 0);
 // v.push_back(8);
 
 // 给vector重新赋值,可能会引起底层容量改变
 v.assign(100, 8);
 
 /*
 出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。
 解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。
 */
 while(it != v.end())
 {
 cout<< *it << " " ;
 ++it;
 }
 cout<<endl;
 return 0;
}

插入时扩容会导致原pos的迭代器失效,所以要记录长度更新pos

2.指定位置元素的删除操作 erase

#include <iostream>
using namespace std;
#include <vector>
int main()
{
 int a[] = { 1, 2, 3, 4 };
 vector<int> v(a, a + sizeof(a) / sizeof(int));
 // 使用find查找3所在位置的iterator
 vector<int>::iterator pos = find(v.begin(), v.end(), 3);
 // 删除pos位置的数据,导致pos迭代器失效。
 v.erase(pos);
 cout << *pos << endl; // 此处会导致非法访问
 return 0;
}

erase删除pos位置的元素后,pos位置之后的元素会往前移,没有导致底层空间改变,理论上迭代器不会失效,但如果pos刚好是最后一个元素,删完之后就是end的位置,end是没有元素的,pos就失效了。因此删除任意位置元素vs就认为迭代器已经失效,会报错

下面是删除所有偶数的功能,第2个是正确的,通过返回值更新pos,迭代器就不会失效

#include <iostream>
using namespace std;
#include <vector>
int main()
{
 vector<int> v{ 1, 2, 3, 4 };
 auto it = v.begin();
 while (it != v.end())
 {
 if (*it % 2 == 0)
 v.erase(it);
 ++it;
 }
 
 return 0;
}
int main()
{
 vector<int> v{ 1, 2, 3, 4 };
 auto it = v.begin();
 while (it != v.end())
 {
 if (*it % 2 == 0)
 it = v.erase(it);
 else
 ++it;
 }
 return 0;
}

3.liux下,g++编译器对迭代器的检测不严格,没有vs极端

// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{
 vector<int> v{1,2,3,4,5};
 for(size_t i = 0; i < v.size(); ++i)
 cout << v[i] << " ";
 cout << endl;
 auto it = v.begin();
 cout << "扩容之前,vector的容量为: " << v.capacity() << endl;
 // 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效 
 v.reserve(100);
 cout << "扩容之后,vector的容量为: " << v.capacity() << endl;
 
 // 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会
 // 虽然可能运行,但是输出的结果是不对的
 while(it != v.end())
 {
 cout << *it << " ";
 ++it;
 }
 cout << endl;
 return 0;
}
程序输出:
1 2 3 4 5
扩容之前,vector的容量为: 5
扩容之后,vector的容量为: 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{
 vector<int> v{1,2,3,4,5};
 vector<int>::iterator it = find(v.begin(), v.end(), 3);
 v.erase(it);
  cout << *it << endl;
 while(it != v.end())
 {
 cout << *it << " ";
 ++it;
 }
 cout << endl;
 return 0;
}
程序可以正常运行,并打印:
4
4 5
 
// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{
 vector<int> v{1,2,3,4,5};
 // vector<int> v{1,2,3,4,5,6};
 auto it = v.begin();
 while(it != v.end())
 {
 if(*it % 2 == 0)
 v.erase(it);
 ++it;
 }
 for(auto e : v)
 cout << e << " ";
 cout << endl;
 return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[@VM-0-3-centos 20220114]$ ./a.out
1 3 5
=========================================================
// 使用第二组数据时,程序最终会崩溃
[@VM-0-3-centos 20220114]$ vim testVector.cpp
[@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[@VM-0-3-centos 20220114]$ ./a.out
Segmentation fault

从上面是三个例子可以看出:SGI STL迭代器失效并不一定崩溃,但运行结果肯定不对,it不在begin和end范围,肯定会崩溃

4.与vector类似,string插入+扩容+erase之后,迭代器也会失效

#include <string>
void TestString()
{
 string s("hello");
 auto it = s.begin();
 // 放开之后代码会崩溃,因为resize到20会string会进行扩容
 // 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了
 // 后序打印时,再访问it指向的空间程序就会崩溃
 //s.resize(20, '!');
 while (it != s.end())
 {
 cout << *it;
 ++it;
 }
 cout << endl;
 it = s.begin();
 while (it != s.end())
 {
 it = s.erase(it);
 // 按照下面方式写,运行时程序会崩溃,因为erase(it)之后
 // it位置的迭代器就失效了
 // s.erase(it); 
 ++it;
 }
}

迭代器失效,对迭代器重新赋值

举报

相关推荐

0 条评论