1. 程式人生 > >STL原始碼剖析--vector

STL原始碼剖析--vector

vector容器概述
      vector的資料安排以及操作方式,與array非常相似。兩者的唯一區別在於空間的運用的靈活性。array是靜態空間,一旦配置了就不能改變;要換個大(或小)一點的房子,可以,一切瑣細都得由客戶端自己來:首先配置一塊新空間,然後將元素從舊址一一搬往新址,再把原來的空間釋還給系統。vector是動態空間,隨著元素的加入,它的內部機制會自行擴充空間以容納新元素。因此,vector的運用對於記憶體的合理利用與運用的靈活性有很大的幫助,我們再也不必因為害怕空間不足而一開始要求一個大塊頭的array了,我們可以安心使用array,吃多少用多少。
      vector的實現技術,關鍵在於其對大小的控制以及重新配置時的資料移動效率。一旦vector的舊有空間滿載,如果客戶端每新增一個元素,vector的內部只是擴充一個元素的空間,實為不智。因為所謂擴充空間(不論多大),一如稍早所說,是”配置新空間/資料移動/釋還舊空間
“的大工程,時間成本很高,應該加入某種未雨綢繆的考慮。稍後我們便可看到SGI vector的空間配置策略了。
      另外,由於vector維護的是一個連續線性空間,所以vector支援隨機存取
      注意:vector動態增加大小時,並不是在原空間之後持續新空間(因為無法保證原空間之後尚有可供配置的空間),而是以原大小的兩倍另外配置一塊較大的空間,然後將原內容拷貝過來,然後才開始在原內容之後構造新元素,並釋放原空間。因此,對vector的任何操作,一旦引起空間重新配置,指向原vector的所有迭代器就都失效了。這是程式設計師易犯的一個錯誤,務需小心。

以下是vector定義的原始碼摘錄:

#include<iostream>
using namespace std;
#include<memory.h>  

// alloc是SGI STL的空間配置器
template <class T, class Alloc = alloc>
class vector
{
public:
	// vector的巢狀型別定義,typedefs用於提供iterator_traits<I>支援
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type* iterator;
	typedef value_type& reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
protected:
	// 這個提供STL標準的allocator介面
	typedef simple_alloc <value_type, Alloc> data_allocator;

	iterator start;               // 表示目前使用空間的頭
	iterator finish;              // 表示目前使用空間的尾
	iterator end_of_storage;      // 表示實際分配記憶體空間的尾

	void insert_aux(iterator position, const T& x);

	// 釋放分配的記憶體空間
	void deallocate()
	{
		// 由於使用的是data_allocator進行記憶體空間的分配,
		// 所以需要同樣使用data_allocator::deallocate()進行釋放
		// 如果直接釋放, 對於data_allocator內部使用記憶體池的版本
		// 就會發生錯誤
		if (start)
			data_allocator::deallocate(start, end_of_storage - start);
	}

	void fill_initialize(size_type n, const T& value)
	{
		start = allocate_and_fill(n, value);
		finish = start + n;                         // 設定當前使用記憶體空間的結束點
		// 構造階段, 此實作不多分配記憶體,
		// 所以要設定記憶體空間結束點和, 已經使用的記憶體空間結束點相同
		end_of_storage = finish;
	}

public:
	// 獲取幾種迭代器
	iterator begin() { return start; }
	iterator end() { return finish; }

	// 返回當前物件個數
	size_type size() const { return size_type(end() - begin()); }
	size_type max_size() const { return size_type(-1) / sizeof(T); }
	// 返回重新分配記憶體前最多能儲存的物件個數
	size_type capacity() const { return size_type(end_of_storage - begin()); }
	bool empty() const { return begin() == end(); }
	reference operator[](size_type n) { return *(begin() + n); }

	// 本實作中預設構造出的vector不分配記憶體空間
	vector() : start(0), finish(0), end_of_storage(0) {}


	vector(size_type n, const T& value) { fill_initialize(n, value); }
	vector(int n, const T& value) { fill_initialize(n, value); }
	vector(long n, const T& value) { fill_initialize(n, value); }

	// 需要物件提供預設建構函式
	explicit vector(size_type n) { fill_initialize(n, T()); }

	vector(const vector<T, Alloc>& x)
	{
		start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
		finish = start + (x.end() - x.begin());
		end_of_storage = finish;
	}

	~vector()
	{
		// 析構物件
		destroy(start, finish);
		// 釋放記憶體
		deallocate();
	}

	vector<T, Alloc>& operator=(const vector<T, Alloc>& x);

	// 提供訪問函式
	reference front() { return *begin(); }
	reference back() { return *(end() - 1); }

	////////////////////////////////////////////////////////////////////////////////
	// 向容器尾追加一個元素, 可能導致記憶體重新分配
	////////////////////////////////////////////////////////////////////////////////
	//                          push_back(const T& x)
	//                                   |
	//                                   |---------------- 容量已滿?
	//                                   |
	//               ----------------------------
	//           No  |                          |  Yes
	//               |                          |
	//               ↓                          ↓
	//      construct(finish, x);       insert_aux(end(), x);
	//      ++finish;                           |
	//                                          |------ 記憶體不足, 重新分配
	//                                          |       大小為原來的2倍
	//      new_finish = data_allocator::allocate(len);       <stl_alloc.h>
	//      uninitialized_copy(start, position, new_start);   <stl_uninitialized.h>
	//      construct(new_finish, x);                         <stl_construct.h>
	//      ++new_finish;
	//      uninitialized_copy(position, finish, new_finish); <stl_uninitialized.h>
	////////////////////////////////////////////////////////////////////////////////

	void push_back(const T& x)
	{
		// 記憶體滿足條件則直接追加元素, 否則需要重新分配記憶體空間
		if (finish != end_of_storage)
		{
			construct(finish, x);
			++finish;
		}
		else
			insert_aux(end(), x);
	}


	////////////////////////////////////////////////////////////////////////////////
	// 在指定位置插入元素
	////////////////////////////////////////////////////////////////////////////////
	//                   insert(iterator position, const T& x)
	//                                   |
	//                                   |------------ 容量是否足夠 && 是否是end()?
	//                                   |
	//               -------------------------------------------
	//            No |                                         | Yes
	//               |                                         |
	//               ↓                                         ↓
	//    insert_aux(position, x);                  construct(finish, x);
	//               |                              ++finish;
	//               |-------- 容量是否夠用?
	//               |
	//        --------------------------------------------------
	//    Yes |                                                | No
	//        |                                                |
	//        ↓                                                |
	// construct(finish, *(finish - 1));                       |
	// ++finish;                                               |
	// T x_copy = x;                                           |
	// copy_backward(position, finish - 2, finish - 1);        |
	// *position = x_copy;                                     |
	//                                                         ↓
	// data_allocator::allocate(len);                       <stl_alloc.h>
	// uninitialized_copy(start, position, new_start);      <stl_uninitialized.h>
	// construct(new_finish, x);                            <stl_construct.h>
	// ++new_finish;
	// uninitialized_copy(position, finish, new_finish);    <stl_uninitialized.h>
	// destroy(begin(), end());                             <stl_construct.h>
	// deallocate();
	////////////////////////////////////////////////////////////////////////////////

	iterator insert(iterator position, const T& x)
	{
		size_type n = position - begin();
		if (finish != end_of_storage && position == end())
		{
			construct(finish, x);
			++finish;
		}
		else
			insert_aux(position, x);
		return begin() + n;
	}

	iterator insert(iterator position) { return insert(position, T()); }

	void pop_back()
	{
		--finish;
		destroy(finish);
	}

	iterator erase(iterator position)
	{
		if (position + 1 != end())
			copy(position + 1, finish, position);
		--finish;
		destroy(finish);
		return position;
	}


	iterator erase(iterator first, iterator last)
	{
		iterator i = copy(last, finish, first);
		// 析構掉需要析構的元素
		destroy(i, finish);
		finish = finish - (last - first);
		return first;
	}

	// 調整size, 但是並不會重新分配記憶體空間
	void resize(size_type new_size, const T& x)
	{
		if (new_size < size())
			erase(begin() + new_size, end());
		else
			insert(end(), new_size - size(), x);
	}
	void resize(size_type new_size) { resize(new_size, T()); }

	void clear() { erase(begin(), end()); }

protected:
	// 分配空間, 並且複製物件到分配的空間處
	iterator allocate_and_fill(size_type n, const T& x)
	{
		iterator result = data_allocator::allocate(n);
		uninitialized_fill_n(result, n, x);
		return result;
	}

	// 提供插入操作
	////////////////////////////////////////////////////////////////////////////////
	//                 insert_aux(iterator position, const T& x)
	//                                   |
	//                                   |---------------- 容量是否足夠?
	//                                   ↓
	//              -----------------------------------------
	//        Yes   |                                       | No
	//              |                                       |
	//              ↓                                       |
	// 從opsition開始, 整體向後移動一個位置                     |
	// construct(finish, *(finish - 1));                    |
	// ++finish;                                            |
	// T x_copy = x;                                        |
	// copy_backward(position, finish - 2, finish - 1);     |
	// *position = x_copy;                                  |
	//                                                      ↓
	//                            data_allocator::allocate(len);
	//                            uninitialized_copy(start, position, new_start);
	//                            construct(new_finish, x);
	//                            ++new_finish;
	//                            uninitialized_copy(position, finish, new_finish);
	//                            destroy(begin(), end());
	//                            deallocate();
	////////////////////////////////////////////////////////////////////////////////

	template <class T, class Alloc>
	void insert_aux(iterator position, const T& x)
	{
		if (finish != end_of_storage)    // 還有備用空間
		{
			// 在備用空間起始處構造一個元素,並以vector最後一個元素值為其初值
			construct(finish, *(finish - 1));
			++finish;
			T x_copy = x;
			copy_backward(position, finish - 2, finish - 1);
			*position = x_copy;
		}
		else   // 已無備用空間
		{
			const size_type old_size = size();
			const size_type len = old_size != 0 ? 2 * old_size : 1;
			// 以上配置元素:如果大小為0,則配置1(個元素大小)
			// 如果大小不為0,則配置原來大小的兩倍
			// 前半段用來放置原資料,後半段準備用來放置新資料

			iterator new_start = data_allocator::allocate(len);  // 實際配置
			iterator new_finish = new_start;
			// 將記憶體重新配置
			try
			{
				// 將原vector的安插點以前的內容拷貝到新vector
				new_finish = uninitialized_copy(start, position, new_start);
				// 為新元素設定初值 x
				construct(new_finish, x);
				// 調整水位
				++new_finish;
				// 將安插點以後的原內容也拷貝過來
				new_finish = uninitialized_copy(position, finish, new_finish);
			}
			catch(...)
			{
				// 回滾操作
				destroy(new_start, new_finish);
				data_allocator::deallocate(new_start, len);
				throw;
			}
			// 析構並釋放原vector
			destroy(begin(), end());
			deallocate();

			// 調整迭代器,指向新vector
			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + len;
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	// 在指定位置插入n個元素
	////////////////////////////////////////////////////////////////////////////////
	//             insert(iterator position, size_type n, const T& x)
	//                                   |
	//                                   |---------------- 插入元素個數是否為0?
	//                                   ↓
	//              -----------------------------------------
	//        No    |                                       | Yes
	//              |                                       |
	//              |                                       ↓
	//              |                                    return;
	//              |----------- 記憶體是否足夠?
	//              |
	//      -------------------------------------------------
	//  Yes |                                               | No
	//      |                                               |
	//      |------ (finish - position) > n?                |
	//      |       分別調整指標                              |
	//      ↓                                               |
	//    ----------------------------                      |
	// No |                          | Yes                  |
	//    |                          |                      |
	//    ↓                          ↓                      |
	// 插入操作, 調整指標           插入操作, 調整指標           |
	//                                                      ↓
	//            data_allocator::allocate(len);
	//            new_finish = uninitialized_copy(start, position, new_start);
	//            new_finish = uninitialized_fill_n(new_finish, n, x);
	//            new_finish = uninitialized_copy(position, finish, new_finish);
	//            destroy(start, finish);
	//            deallocate();
	////////////////////////////////////////////////////////////////////////////////

	template <class T, class Alloc>
	void insert(iterator position, size_type n, const T& x)
	{
		// 如果n為0則不進行任何操作
		if (n != 0)
		{
			if (size_type(end_of_storage - finish) >= n)
			{      // 剩下的備用空間大於等於“新增元素的個數”
				T x_copy = x;
				// 以下計算插入點之後的現有元素個數
				const size_type elems_after = finish - position;
				iterator old_finish = finish;
				if (elems_after > n)
				{
					// 插入點之後的現有元素個數 大於 新增元素個數
					uninitialized_copy(finish - n, finish, finish);
					finish += n;    // 將vector 尾端標記後移
					copy_backward(position, old_finish - n, old_finish);
					fill(position, position + n, x_copy); // 從插入點開始填入新值
				}
				else
				{
					// 插入點之後的現有元素個數 小於等於 新增元素個數
					uninitialized_fill_n(finish, n - elems_after, x_copy);
					finish += n - elems_after;
					uninitialized_copy(position, old_finish, finish);
					finish += elems_after;
					fill(position, old_finish, x_copy);
				}
			}
			else
			{   // 剩下的備用空間小於“新增元素個數”(那就必須配置額外的記憶體)
				// 首先決定新長度:就長度的兩倍 , 或舊長度+新增元素個數
				const size_type old_size = size();
				const size_type len = old_size + max(old_size, n);
				// 以下配置新的vector空間
				iterator new_start = data_allocator::allocate(len);
				iterator new_finish = new_start;
				__STL_TRY
				{
					// 以下首先將舊的vector的插入點之前的元素複製到新空間
					new_finish = uninitialized_copy(start, position, new_start);
					// 以下再將新增元素(初值皆為n)填入新空間
					new_finish = uninitialized_fill_n(new_finish, n, x);
					// 以下再將舊vector的插入點之後的元素複製到新空間
					new_finish = uninitialized_copy(position, finish, new_finish);
				}
#         ifdef  __STL_USE_EXCEPTIONS
				catch(...)
				{
					destroy(new_start, new_finish);
					data_allocator::deallocate(new_start, len);
					throw;
				}
#         endif /* __STL_USE_EXCEPTIONS */
				destroy(start, finish);
				deallocate();
				start = new_start;
				finish = new_finish;
				end_of_storage = new_start + len;
			}
		}
	}
};