4.2 vector
template <class T, class Alloc = alloc>
class vector{
typedef T value_type; typedef value_type* iterator;
protected:
iterator start; // 表示目前使用空間的頭
iterator finish; // 表示目前使用空間的尾
iterator end_of_storage;// 表示目前可用空間的尾
...
};
成员函数举例:注意其中的内存管理
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x)
{
if (n != 0) { // 當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(...) {
// 如有異常發生,實現"commit or rollback" semantics.
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
// 以㆘清除並釋放舊的vector
destroy(start, finish); //全局函数
deallocate();
// 以㆘調整水位標記
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
4.3 list
1、list的节点(node)
template <class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev;// 型別為void*。其实可設為__list_node<T>*
void_pointer next;
T data;
};
2、list的迭代器
template<class T, class Ref, class Ptr>
struct __list_iterator{
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;// 迭代器內部當然要有㆒個原生指標,指向list的節點
// constructor
__list_iterator(link_type x) : node(x) {}
__list_iterator() {}
__list_iterator(const iterator& x) : node(x.node) {}
bool operator==(const self& x) const { return node == x.node; }
bool operator!=(const self& x) const { return node != x.node; }
// 以㆘對迭代器取值(dereference),取的是節點的資料值。
reference operator*() const { return (*node).data; }
// 以㆘是迭代器的成員存取(member access)運算子的標準作法。
pointer operator->() const { return &(operator*()); }
// 對迭代器累加1,就是前進㆒個節點
self& operator++() {
node = (link_type)((*node).next);
return *this;
}
self operator++(int) {
self tmp = *this;
++*this;
return tmp;
}
// 對迭代器遞減1,就是後退㆒個節點
self& operator--() {
node = (link_type)((*node).prev);
return *this;
}
self operator--(int) {
self tmp = *this;
--*this;
return tmp;
}
};
3、list——实现为一个环状双向列表
template <class T, class Alloc = alloc> // 預設使用alloc 為配置器
class list{
protected:
typedef __list_node<T> list_node;
public:
typedef list_node* link_type;
protected:
link_type node; // 只要㆒個指標,便可表示整个环状双向链表,node指向置于尾端的空节点
...
public:
iterator begin() { return (link_type)((*node).next); }
iterator end() { return node; }
};
4、元素操作
insert, push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort
template <class T, class Alloc>
void list<T, Alloc>::unique() {
iterator first = begin();
iterator last = end();
if (first == last) return; // 空串列,什麼都不必做。
iterator next = first;
while (++next != last) { // 巡訪每㆒個節點
if (*first == *next) // 如果在此區段㆗有相同的元素
erase(next); // 移除之
else
first = next; // 調整指针
next = first; // 修正區段范围
}
}
list不能使用STL算法的sort(),必须使用自己的成员函数sort,因为STL算法sort()只接受RandomAccessIterator。
// 將[first,last) 內的所有元素搬移到position 之前。它是spice(), reserve(), merge()的基础。
void transfer(iterator position, iterator first, iterator last)
// “本函式採用quick sort”。这是书中原话,我觉得更像是归并排序的迭代形式。
template <class T, class Alloc>
void list<T, Alloc>::sort() {
// 以㆘判斷,如果是空白串列,或僅有㆒個元素,就不做任何動作。
// 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
if (node->next == node || link_type(node->next)->next == node)
return;
// ㆒些新的lists,做為㆗介資料存放區
list<T, Alloc> carry;
list<T, Alloc> counter[64];
int fill = 0;
while (!empty()) {
carry.splice(carry.begin(), *this, begin());
int i = 0;
while(i < fill && !counter[i].empty()) {
counter[i].merge(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
if (i == fill) ++fill;
}
for (int i = 1; i < fill; ++i)
counter[i].merge(counter[i-1]);
swap(counter[fill-1]);
}
4.4 deque
虽然deque也提供random access iterator,但是并不是普通指针,所以尽可能使用vector。对deque进行的排序操作,为了最高效率,可将deque先完整复制到一个vector上,将vector排序后(利用STL sort算法),再复制会deque。
1、deque的中控器
deque采用一块所谓的map(不是STL的map容器),为一小块连续空间,其中每个元素都是指针,指向较大的连续线性空间(缓冲器),缓冲区才是deque的存储空间主体。
2、deque的迭代器
template <class T, class Ref, class Ptr,size_t BufSiz>
struct __deque_iterator{ // 未繼承std::iterator
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;
static size_t buffer_size() {return __deque_buf_size(BufSiz, sizeof(T)); }
// 未繼承std::iterator,所以必須自行撰寫五個必要的迭代器相應型別(第3章)
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T** map_pointer;
typedef __deque_iterator self;
// 保持與容器的聯結
T* cur; // 此迭代器所指之緩衝區㆗的現行(current)元素
T* first; // 此迭代器所指之緩衝區的頭
T* last; // 此迭代器所指之緩衝區的尾(含備用空間)
map_pointer node; // 指向管控㆗心
...
};
// 以下實現隨機存取。迭代器可以直接跳躍n個距離。
self& operator+=(difference_type n) {
difference_type offset = n + (cur - first);
if (offset >= 0 && offset < difference_type(buffer_size()))
// 標的位置在同㆒緩衝區內
cur += n;
else {
// 標的位置不在同㆒緩衝區內
difference_type node_offset =
offset > 0 ? offset / difference_type(buffer_size())
: -difference_type((-offset - 1) / buffer_size()) - 1;
// 切換至正確的節點(亦即緩衝區)
set_node(node + node_offset);
// 切換至正確的元素
cur = first + (offset - node_offset * difference_type(buffer_size()));
}
return *this;
}
// 參考 More Effective C++, item22: Consider using op= instead of
// stand-alone op. A = B + n;
self operator+(difference_type n) const {
self tmp = *this;
return tmp +=n; // 喚起operator+=
}
3、deque的数据结构
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque{
public: // Basic types
typedef T value_type;
typedef value_type* pointer;
typedef size_t size_type;
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
protected: // Internal typedefs
// 元素的指標的指標(pointer of pointer of T)
typedef pointer* map_pointer;
protected: // Data members
iterator start; // 表現第㆒個節點。
iterator finish; // 表現最後㆒個節點
map_pointer map; // 指向map,map是塊連續空間,其內的每個元素
// 都是㆒個指標(稱為節點),指向㆒塊緩衝區。
size_type map_size; // map內可容納多少指標。
...
};
reference back() {
iterator tmp = finish;
--tmp; // 喚起__deque_iterator<>::operator--
return *tmp;// 喚起__deque_iterator<>::operator*
// 以㆖㆔行何不改為:return *(finish-1);
// 因為__deque_iterator<> 沒有為(finish-1) 定義運算子?!
}