STL中vector的简单实现

allocator类型

new实现了分配内存和初始化的整合,但是在分配大块内存时,对所有位置都调用构造函数是低效的,应该在使用时才初始化该位置。所以必须单独进行内存分配和初始化。依赖于allocator的

T* allocate(size_t);  //分配内存
construct(T*, args);//构造函数
destroy(T*);//析构
deallocate(T*, size_t);//释放内存

vector容器

容器分为两部分,first~ finish是分配空间且初始化元素的,finish~ end_of_storage是只分配空间。有两种操作:对元素操作,构造/析构对象,影响size();对空间操作,影响capcity()。
vector的size随元素增减而变化,但capcity只增加不减少。除非移动语义下替换容器空间。remove时,是把值不等于val的元素移到前面,不改变容器size。erase时,析构指定位置的元素,影响size,不影响capcity。

要区分元素是指针还是对象。如果元素是对象,释放元素空间时先析构再释放;如果元素是指针,那么数组存储指针,然后指针指向一块内存,释放元素空间时只是释放容器的空间,指针指向的内存却无法释放。

namespace ch {
template<typename T>
class Vector
{
public:
	typedef T* iterator;

	friend iterator remove(iterator first, iterator last, T val);
private:
	iterator start;
	iterator finish;
	iterator end_of_storage;
	static allocator<T> alloc;


public:
	Vector() :start(nullptr), finish(nullptr), end_of_storage(nullptr) {}
	Vector(const Vector& v)//拷贝构造
	{
		size_t n = v.finish - v.start;
		iterator ptr = v.start;
		finish = start = alloc.allocate(n);
		while (ptr != v.finish)
		{
			alloc.construct(finish++, *ptr++);
		}
		end_of_storage = finish;
	}
	Vector(const Vector&& v)//移动构造
	{
		start = v.start;
		finish = v.finish;
		end_of_storage = v.end_of_storage;
		v.start = v.finish = v.end_of_storage = nullptr;
	}
	~Vector()
	{//析构start~finish元素,释放start~end_of_storage空间
		iterator ptr = start;
		while (ptr != finish)
			alloc.destroy(ptr++);
		alloc.deallocate(start, end_of_storage - start);
	}

	Vector& operator=(const Vector& v)
	{
		if (v == *this) return *this;
		//析构元素
		iterator ptr = start;
		while (ptr != finish)
			alloc.destroy(ptr++);
		//如果新空间比原有空间大,就重新分配,否则不重新分配空间。
		size_t n = v.end_of_storage - v.start;
		if (n > end_of_storage - start)
		{
			alloc.deallocate(start, end_of_storage - start);
			finish = start = alloc.allocate(n);
			ptr = v.start;
			while (ptr != v.finish)
			{
				alloc.construct(finish++, *ptr++);
			}
			end_of_storage = start + n;
		}
		else {
			finish = start;
			ptr = v.start;
			while (ptr != v.finish)
			{
				alloc.construct(finish++, *ptr++);
			}
		}
		return *this;
	}
	Vector& operator=(const Vector&& v)
	{//移动赋值运算符,另一个容器的空间偷过来,所以capcity可能会减小。
		if (v == *this) return *this;
		//析构元素,并释放空间。
		iterator ptr = start;
		while (ptr != finish)
			alloc.destroy(ptr++);
		alloc.deallocate(start, end_of_storage - start);

		finish = v.finish;
		start = v.start;
		end_of_storage = v.end_of_storage;
		v.finish = v.start = v.end_of_storage = nullptr;
	}
	/*erase:析构某位置元素,并返回下一元素的迭代器。
	*/
	iterator erase(iterator first, iterator last)
	{
		iterator a = first, b = last;
		while (b != finish)
			* a++ = *b++;

		while (a != finish)
			alloc.destroy(a++);
		finish = finish - (last - first);
		return first;
	}
	iterator erase(iterator pos)
	{
		iterator a = pos, b = pos + 1;
		while (b != finish)
			* a++ = *b++;
		finish--;
		alloc.destroy(finish);
		return pos;
	}

	void  push_back(const T& t)
	{
		if (finish == end_of_storage)
		{
			size_t n = end_of_storage - start > 0 ? 2 * (end_of_storage - start) : 1;
			//先分配新空间,拷贝值,再释放原空间
			iterator new_start = nullptr, new_finish = nullptr;
			new_finish = new_start = alloc.allocate(n);
			iterator old_p = start, new_p = new_start;
			while (old_p != finish)
				alloc.construct(new_p++, *old_p++);
			new_finish = new_p;

			old_p = start;
			while (old_p != finish)
				alloc.destroy(old_p++);
			alloc.deallocate(start, end_of_storage - start);

			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + n;
		}

		alloc.construct(finish, t);
		finish++;
	}

	void push_back(const T&& t)
	{
		if (finish == end_of_storage)
		{
			size_t n = end_of_storage - start > 0 ? 2 * (end_of_storage - start) : 1;
			//先分配新空间,拷贝值,再释放原空间
			iterator new_start = nullptr, new_finish = nullptr;
			new_finish = new_start = alloc.allocate(n);
			iterator old_p = start;
			iterator new_p = new_start;
			while (old_p != finish)
				alloc.construct(new_p++, *old_p++);
			new_finish = new_p;

			old_p = start;
			while (old_p != finish)
				alloc.destroy(old_p++);
			alloc.deallocate(start, end_of_storage - start);

			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + n;
		}

		alloc.construct(finish, std::move(t));
		finish++;
	}
	size_t size() const { return finish - start; }
	size_t capcity() const { return end_of_storage - start; }
	iterator begin() const { return start; }
	iterator end() const { return finish; }
};

template<typename T>
allocator<T> Vector<T>::alloc;

/*类模板的非约束参数的友元函数。
	remove:将与目标值不相等的元素拷贝到前面,返回不相等区下一个位置。
*/
template<typename T>
typename ch::Vector<T>::iterator remove(typename ch::Vector<T>::iterator first, 
		typename ch::Vector<T>::iterator last, T val)
{
	typedef typename ch::Vector<T>::iterator iterator;
	iterator fast = first, low = first;
	while (fast != last)
	{
		if (*fast != val)
			*low++ = *fast++;
		else
			fast++;
	}
	return low;
}
};

常见vector操作

ch::Vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(3);
v.push_back(5);

//删除等于3的所有元素
v.erase(ch::remove<ch::Vector<int>::iterator, int>(v.begin(), v.end(), 3), v.end());
//删除所有元素,当然容器空间没有释放。
ch::Vector<int>::iterator it = v.begin();
while (it != v.end())
	it = v.erase(it);
  1. 移动语义
    从源对象向新对象拷贝时会占用大量时间,当源对象时临时对象(右值)或不再使用时(可转变为右值),可使用移动语义。
    (1)首先利用std::move将对象转换成右值
    (2)把源对象的内部指针拷贝过来,并将其赋值为nullptr,避免重复释放内存。
    (3)源对象成为右值对象后不就会被系统释放掉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值