STL中的vector

    在上一篇中,我分析了nginx中的动态数组, 作为对比这里再分析一下SGI STL

中的动态数组(vector)。

    在开篇之前想借此文大家一个问题,STL在大家的工程中用得多吗?本人现在的

公司C++的代码都是用MFC开发的,公司项目也算比较多的,但是在开发过程中用

上标准库的真的不太多!?

1. vector 源代码分析

    STL中的vector也可以认为是对array的包装和升级。

    - vector 在其内部保持着一个原始的数组(一块连续的内存区域),但是提供了计算size,capacity,以及

       动态扩展的能力。

    - vector 可以认为是一种全新的数据类型,所以必须重载=, []等运算符

    - 提供了push_back, pop_back,clear,erase, resize等操作元素的能力

    - 提供empty , size,capacity等判断内部元素的能力

    - 支持迭代

1.1 vector的属性

    在vector中定义了三个成员变量,代码如下:

 namespace SLD
{
	template <class T>
	class vector
	{
	private:
		T*		m_start;//使用空间的开头
		T*		m_finish;//使用空间的末尾
		T*		m_end_of_storage//可用空间的末尾
	};
}

 

其中 m_finish – m_start 就等于这个vector的size,

m_end_of_storage – m_start就等于这个vector的capacity。

1.2 vector的构造

    vector支持五种类型的初始化化, 所以它就必须有5个构造函数:

 explicit vector():m_start(0), m_finish(0), m_end_of_storage(0) {}

vector(size_t n, const T& value) 
{
	Base(n);
	m_finish = uninitialized_fill_n(m_start, n, value);
}

explicit vector(size_t n)
{
	Base(n);
	m_finish = uninitialized_fill_n(m_start, n, T());
}
		
template <class p>
vector(const SLD::vector<p>& x)
{
	Base(x.size());
	uninitialized_copy(x.begin(), x.end(), m_start);
}

vector(T* first, T* last) 
{
	Base(last - first);
	uninitialized_copy(first, last, m_start);

}

 

    在这里, 我为了代码的简单, 去掉了STL中从alloc分配内存的动作, 而直接用new delete,

这样管理内存,性能当然很差了, 但是用来说明vector却足够了, 所以uninitialized_copy

和uninitialized_fill_n 函数 我也仿造STL中从新写了一个, 不然的话光是内存分配的动作就能

拉出一大堆的代码。下面是我仿造的几个函数:

 private:
//为了简便我在这里重新模拟了uninitialized_fill_n
//在SLT中它是在stl_uninitialized.h中单独实现的
T* uninitialized_fill_n(T* first, size_t n, const T& value)
{
	assert(first);
	assert(n >= 0);
			
	for (int i = 0; i < n; ++i)
		*(first + i) = value;

	return first + n;//[m_start, m_finish)
}

void uninitialized_copy(T* source_begin, T* source_end, T* dest)
{
	for (int i = 0; i < (source_end - source_begin); ++i)
	{
		*(dest + i) = *(source_begin + i);
	}
}

void Base (size_t n)
{
	//m_start = _M_allocate(__n);原本是从alloc中分配的,这里为了简单用malloc代替
	m_start = new T[n*2];//这个是我写的, 用来代替原来的从alloc中分配的,
						//这样做的原因是为了得到最少的能编译通过的代码
	m_finish = m_start;
	m_end_of_storage = m_start + 2*n;
}


  这样我们就可以写下如下的测试代码了:

 SLD::vector<int> test0;
SLD::vector<int> test1(10,4);
SLD::vector<int> test2(10);
SLD::vector<int> test3(test1);
SLD::vector<int> test4(test1.begin(), test1.end());

 

 

1.3 vector的元素的迭代

     vector必须支持迭代功能,说到迭代功能,不得不说下STL种的迭代器。

迭代器中STL中扮演着很重要的角色. STL的核心思想就是:将数据结构和算法分离。

而迭代器就是作为数据结构和算法的粘合层而存在的。在STL中,每一个容器而有一个自己

的迭代器, 而vector的迭代器就是一个普通的指针。所以在vector中实现迭代功能就非常

的简单了。代码如下:

 T* begin(){return m_start;}
T* end(){return m_finish;}


然后调用的使用只需:

 for (int* p = test1.begin(); p != test1.end(); ++p)
{
	std::cout<<*p<<std::endl;
}

 

 

1.4 vector的元素判断

    vector 提供了计算大小, 容量, 是不是空 等一系列的判断,实现起来也非常简单:

 size_t size(){return size_t(m_finish - m_start);}

size_t capacity() const 
{
	return size_t(m_end_of_storage - m_start);
}

bool empty()const {return begin() == end()}

 

 

1.5 vector的运算符

   在使用vector的时候,可以吧它认为是一种全新的数据类型, 所以[], ==, != , <= 等运算符

的重载是必须的。首先我们看下它是如何进行[]和= 的:

 T&	operator[](size_t n) {return *(begin() + n);}
		
template <class T1>
vector<T1>& operator=(const vector<T1>& x)
{
	if (&x != this)
	{
		const size_t xlen = x.size();
		if (xlen > capacity())
		{
			//从新分配内存
			delete [] m_start;
			Base[xlen];

		}
		else (size() >= xlen )
		{
			T1*p = copy(x.begin(), x.end(), begin());

			delete []  p; //删除多余的
		}
		else
		{
			copy(x.begin(), x.begin() + size(), m_start);
			uninitialized_copy(x.begin() + size(), x.end(), m_finish);
		}
				
		m_finish = m_start + xlen;
	}

	return *this;
}

 

有了实现我们就可以这样使用它了:

test0 = test1;
std::cout<<test0[2]<<endl;

 

然后我们在来看下几个比较运算符的实现:

 	template <class T>
	inline bool operator==(const vector<T>& x, const vector<T>& y)
	{
		return (x.size() == y.size()) &&
			equal(x.begin(), x.end(), y.begin(), y.end());
		//这里直接用了algorithm中的equal算法
	}
	
	template <class T>
	inline bool operator< (const vector<T>& x, const vector<T>& y)
	{
		return lexicographical_compare(x.begin(), x.end(), 
										y.begin(), y.end());
		//还是借用了algorithm中的算法
	}

	template <class T>
	inline bool operator!= (const vector<T>& x, const vector<T>& y)
	{
		return !(x == y);
	}

	template <class T>
	inline bool operator>= (const vector<T>& x, const vector<T>& y)
	{
		return !(x <y);
	}

 

实现起来非常简单了。

1.6 vector的元素的操作

    vector的元素的操作非常多, 这里我就选取其中典型的几个来分析下:

 		void push_back(const T& x)//在末尾增加一个
		{
			if (m_finish != m_end_of_storage)
			{
				construct(m_finish, x);
				++m_finish;
			}
			//else
				// _M_insert_aux(end(), __x);重新分配内存,这里就不继续了
		}

		void pop_back()//在末尾减去一个
		{
			--m_finish;
			destroy(m_finish);
		}

		T* erase(T* position) //将 postition 位置上的元素移除,返回下一个元素
		{
			if (position + 1 != end())
				copy(position + 1, m_finish, position);
			--m_finish;
			destroy(m_finish);
			return position;
		}
		
		T* erase(T* first, T* last)//移除区间[first)中的元素, 返回下一个元素
		{
			T* i = copy(last, m_finish, first);
			destroy(i, m_finish);
			m_finish = m_finish - (last - first);
			return first;
		}

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

//然后这里是在class vector 之外了, 定义了连个函数:
	template<class _T1,class _T2> 
	inline void construct(_T1 _FARQ *_Ptr, const _T2& _Val)
	{	// construct object at _Ptr with value _Val
		void _FARQ *_Vptr = _Ptr;
		::new (_Vptr) _T1(_Val);
	}

	template<class _Ty>
	inline void destroy(_Ty _FARQ *_Ptr)
	{	// destroy object at _Ptr
		_DESTRUCTOR(_Ty, _Ptr);
	}


这几个函数的实现也比较简单, 以 push_back 为例子, 首先它会判断此容器的容量是不是满了, 如果慢了

则需要重新申请内存了, 如果还没有满 则增加一个值吗, 然后调整m_finish的位置。而pop_back, 则刚好

相反,减少一个值,然后改变m_finish的位置。

 

2. 小结

    vector的原理简单, 但是实现起来就复杂了。复杂度和功能是成正比的, STL的野心是很庞大的,导致了

内部实现的代码就复杂了。 不过话说回来,C 语言的哲学理念是:Kiss(keep it simple stupid)(武断,错误,

或者应该更正为simple,但是这里不改了)。 但是C++ 的 哲学理念是什么呢?Perfect?Complex?All-purpose?

转载于:https://www.cnblogs.com/sld666666/archive/2010/07/11/1775276.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值