1. 程式人生 > >Accelerated C++ —— 簡易版std::vector類的實現

Accelerated C++ —— 簡易版std::vector類的實現

#include <memory>
#include <iostream>
#include <algorithm>
namespace Ming {
	template<class T> class vec
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		//typedef typename std::vector<T>::size_type size_type;
		typedef size_t size_type;
		typedef T value_type;
		typedef T& reference;
		typedef const T& const_reference;

		//-------------------------------------建構函式
		//--重寫預設建構函式
		vec() {
			create();
		}
		//--帶參建構函式
		//對於只帶有一個引數的建構函式,使用者只能這樣vec<int> a(100);來呼叫建構函式初始化,不能vec<int> a = 100;
		//即explicit 消除了隱式轉換
		explicit  vec(size_type n, const T& val = T()) {
			create(n, val);
		}
		//--複製建構函式
		vec(const vec &v) {
			std::cout << "複製啦" << std::endl;
			create(v.cbegin(), v.cend());
		}
		//--解構函式
		~vec() {
			uncreate();
		}

		//--------------------------------------過載操作符號
		/*宣告賦值操作符*/
		vec& operator=(const vec&);//相當於vec<T>& vec<T>::operator=(const vec&);
		/* 返回引用,1、方面呼叫a[i]=nums;來修改值2、避免經常複製,效率高*/
		T& operator[](size_type i) {
			return data[i];
		}
		const T& operator[](size_type i)const
		{
			return data[i];
		}

		//---------------------------------------迭代器(對系統指標進行改寫)
		iterator begin() { return data; }
		iterator end() { return avail; }
		const_iterator cbegin() const { return data; }
		const_iterator cend()const { return avail; }

		//---------------------------------------成員函式
		/* 獲取動態陣列大小*/
		size_type size()const { return avail - data; }
		void push_back(const T& val)
		{
			if (avail == limit)//空間不足,重新申請空間
				grow();
			unchecked_append(val);//插入新元素
		}

	private:
		iterator data;
		iterator avail;
		iterator limit;

		std::allocator<T> alloc;

		void create();
		void create(size_type, const_reference);
		void create(const_iterator, const_iterator);

		void uncreate();

		void grow();
		void unchecked_append(const_reference);
	};

	/*賦值操作符實現*/
	/*
	 * !!當用=為一個變數提供一個初始值時,呼叫的是複製建構函式(copy constructor):直接進行賦值
	 * !!當用=為一個變數進行賦值時,呼叫的是operator=函式:先刪除先前的值,在進行賦值
	 */
	template <class T>
	vec<T>& vec<T>::operator=(const vec<T> &rhs)
	{
		std::cout << "賦值啦" << std::endl;
		//****檢查是否自我賦值【若不判斷,則會導致uncreate()銷燬this本身的內容,若rhs=this,則rhs也被銷燬了】
		if (&rhs != this)//this型別是vec*,指向成員函式operator=操作的物件的指標
						//this繫結在左運算元上
		{
			uncreate();//釋放左值this陣列內容
			create(rhs.cbegin(), rhs.cend());//從右值複製給左值
		}
		return *this;
	}

	template <typename  T>
	void vec<T>::create()
	{
		data = avail = limit = nullptr;
	}
	template <typename T>
	void vec<T>::create(size_type n, const_reference val)
	{
		data = alloc.allocate(n);//分配n個能夠存放T的空間,並返回指向這塊空間的首元素的指標
		limit = avail = data + n;//均指向末尾
		std::uninitialized_fill(data, limit, val);//初始化記憶體空間
	}
	template <typename T>
	void vec<T>::create(const_iterator i, const_iterator j)
	{
		data = alloc.allocate(j - i);
		limit = avail = std::uninitialized_copy(i, j, data);//初始化記憶體空間//返回最後一個複製賦值的下一個位置【按道理來講應該是指向空】
	}

	template <typename T>
	void vec<T>::uncreate()
	{
		if (data != nullptr)
		{
			iterator it = avail;
			while (it != data)
				alloc.destroy(--it);//先自減,再用alloc銷燬it指向的記憶體塊

			alloc.deallocate(data, limit - data);//**deallocate()只能傳入非空指標以及長度!!!
		}
		data = limit = avail = nullptr;
	}

	template <typename T>
	void vec<T>::grow()
	{
		//兩個指標相減的結果的型別為ptrdiff_t,它是一種有符號整數型別。
		//減法運算的值為兩個指標在記憶體中的距離(以陣列元素的長度為單位,而非位元組),
		//因為減法運算的結果將除以陣列元素型別的長度。所以該結果與陣列中儲存的元素的型別無關。
		size_type new_size = std::max(2 * (limit - data), static_cast<ptrdiff_t>(1));

		//申請更大(2倍)的記憶體空間
		//將原先內容複製到新的記憶體空間
		iterator new_data = alloc.allocate(new_size);
		iterator new_avail = std::uninitialized_copy(data, avail, new_data);

		//釋放原先舊的記憶體空間
		uncreate();

		data = new_data;
		avail = new_avail;
		limit = new_data + new_size;
	}

	template <typename T>
	void vec<T>::unchecked_append(const_reference val)
	{
		alloc.construct(avail, val);//將val值複製到avail所指的記憶體塊中
		++avail;
	}
}
using namespace Ming;
int main()
{
	vec<int> temp(2, 1);
	temp.push_back(2);
	temp.push_back(3);
	temp.push_back(4);
	for (auto i = temp.begin(); i != temp.end(); ++i)
		std::cout << *i << std::endl;

	vec<int> temp1 = temp;	//複製建構函式
	temp = temp1;		//賦值建構函式

	vec<int> temp2(10);
	//vec<int> temp3 = 10;//只有一個引數的建構函式,有explicit則報錯,無explicit則對
}