研究侯捷的<<STL源码剖析>>有点难度(当然如果您是高手的话会很简单),从Meyer Scott 的200多页的<<Effective STL>>找出要使用的方法的注意事项也不大简单,即使找到也会因不知道内部实现而不理解也很常见,以下提供 Vector 简略的实现原理及使用某些方法时注意事项。
Vector
(sgi-stl-2.91.57)
(i). Vector 的内存分布示意图.(size = finish - satrt, capacity = end_of_storage - start).
(ii). 当vector处于如下状态时,再插入一个元素则会引起内存重新分配及元素移动.如图(ii) – 1, 图(ii) – 2 为在位置pos前插入一元素val后的状态。内存扩大三部曲:(1). 寻找更大的内存空间(2倍);(2). 把原有元素从旧内存移动到新内存; (3). 释放旧内存空间。只要涉及到内存重新分配先前的iterator都失效,涉及到元素移动则看情况.
Vector 的构造函数:
vector();
vector( size_type num, const T &val );
vector( const vector &from );
vector( InputIterator start, InputIterator end );
Vector重载的比较运算符:
v1 == v2; v1 != v2; v1 <= v2; v1 >= v2; v1 < v2; v1 > v2 ; v[]
1. void swap( vector &from );
复杂度: O(1)
功能:交换两个 vector
实现细节: 交换start, finish, end_of_storage. 使用全局函数 swap(T&, T&)
2. int size();
复杂度: O(1)
功能:返回 vector 的元素的个数
实现细节: return finish – start
3. void resize(size_type new_size, cosnt T& value);
resize(size_type new_size);
复杂度:O(|new_size – size()|)
功能:扩大或者缩小vector 的 size (size为元素个数,非capacity)
实现细节:
(1). new_size < size, 调用 erase(begin() + new_size, end()); 删除多余元素.
(2). new_size > size, 调用 insert(end(), new_size-size(), T(value));或者 insert(end(), new_size-size(), T());
注意: (1)涉及元素删除,所以旧的vector在[begin() + new_size, end()) 之间的
iterator 失效. (2). 涉及元素的插入,有可能引起内存重新分配和元素移动,所
以 iterator 很有可能失效.
4. void reserve(size_type n);
复杂度: n > size() 时, O(n - size);
功能: 如果 n > size() 则预留 n 个空间(capacity非size),否则什么都不做.实
现细节:申请新的空间并移动元素,析构旧空间里的元素并释放旧的内存
空间,重新设置satart, finish, end_of_storage。
注意: 调用reserve(size_type n) 后如果有内存分配和元素移动,所以之前的
iterator 全部失效.
5. reverse_iterator rbegin();reverse_iterator rend()
功能:返回 vector 末尾的逆 iterator; 返回 vector 开始的逆 iterator. 因为 reverse_iterator 重载了 ++(相当于正常的 --), -- (相当于正常的 ++)等运算符所以可以像正常 iterator 一样使用. reserve_iterator 的 “*” 源码如下:
reference operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
6. void push_back(const T& value);
复杂度:finish != end_of_storage 为O(1), 否则为 O(size());
功能: 往 vector 的末尾添加 value
实现细节:
(1). If(finish != end_of_storage) // 没有达到尾端
直接添加元素
(2). // 已经达到了尾端. 重新分配内存移动元素.
注意: 由于(2) 存在重新分配内存和移动元素,所以使用push_back()时先前的 iterator 有可能失效.
7. void pop_back();
复杂度: O(1)
功能: 删除 vector 尾端的元素, 但capacity 没有改变。
实现细节: 直接删除即可.
注意: 由于删除时没有检查 vector 是否为空,所以检查是否为空由用户手动检查。
8. size_type max_size();
功能: 返回0xFFFFFFFF最大能存贮多少个T
实现细节:
size_type max_size() const { return size_type(-1) / sizeof(T); }
9. iterator insert(iterator position, const T& x);
复杂度: O(size())
功能: 在 position 前插入元素 x, 并返回指向 x 的iterator.
在position前插入x而不是在后插入x原因在于如果position == end() 则在position后插入则会出现一个漏洞.
实现细节:
(1). Vector 还有剩余空间 && position == end(), 则直接插入.
(2). 如果还有剩余空间则把 [position, end()) 往后移动一个位置再插入 x.
(3). 如果没有剩余空间则重新分配2倍于旧的 vector 的容量,移动元素旧的[start, position), 添加 x, 移动[postion, end()).
注意: (2)涉及[position, end())元素的移动,所以[postion, end())区间的 iterator 失效. (3)涉及内存重新分配元素移动,所以所有的iterator失效。
另外两个版本的 insert. 功能及实现都类似,在此不做说明。
void insert( iterator loc, size_type num, const TYPE &val );
void insert( iterator loc, input_iterator start, input_iterator end );
9. reference front();
功能: 返回 vector 的第一个元素.
10. iterator erase( iterator position );
复杂度: O(size())
功能: 删除 position 并返回下一个元素的 iterator
实现细节:
如果 position != end() 则把[position + 1, end()) 往前移动一个单位,-- finish,
析构最后一个元素(destroy(finish)).
注意: 在删除元素 position 后,先前在[position, end())区间的 iterator 都失效.
如果要删除所有与某一元素相等的元素可使用.erase-remove.如下:
v.erase(remove(v.begin(), v.end(), val), end()).(remove(…)为全局函数,它不删除
元素,只是把元素向前移动把符合条件的元素给覆盖掉而已) 或者使用for()
如下:
For (iterator iter = v.begin(); iter != v.end(); )
{
If (*iter == val)
{
// 释放资源.
Iter = v.erase(iter);
}
Else ++ iter;
}
另一个版本的 erase,功能和实现细节类似,在此不再陈述..
iterator erase(iterator first, iterator last);
11. iterator begin(); iterator end(); bool empty(); void clear();
size_type capacity(); reference back(); 等函数就如它们的名字所描述那样.
参考书目:
1. <<STL 源码剖析>> 侯捷
2. <<C++标准程序库>> 侯捷/孟岩 译
3. <<Effective STL>> Meyer Scott
陈学全
2009-09-12