引用与临时变量
// 《STL源码剖析》,p116
explicit vecotr(size_type n) { fill_initialize(n, T()); }
- 如我们所知,对于常规引用(为了与右值引用区分开来,我们可以称之为左值引用),我们不能将其绑定到要求转换的表达式、字面常量或是返回右值的表达式。
- 右值引用有着完全相反的绑定特性:我们可以将一个右值引用绑定到这类表达式上,但不能将一个右值引用直接绑定到一个左值上。
- 我们不能将一个左值引用绑定到这类表达式上,但我们可以将一个 const 的左值引用或者一个右值引用绑定到这类表达式上。例如:
void fill_initialize(size_type n, const T& value); - 左值有持久的状态,而右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。
- 由于右值引用只能绑定到临时对象,我们得知:所引用的对象将要被销毁,该对象没有其他用户。这两个特性意味着:使用右值引用的代码可以自由地接管所引用的对象的资源。1
迭代器失效
// 《STL源码剖析》,p123
注意,所谓动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大的空间,然后将原内容拷贝过来,然后才开始在原空间之后构造新元素,并释放原空间。因此,对 vector 的任何操作,一旦引起空间重新配置,指向原 vector 的所有迭代器就都失效了。
快速排序
// 《STL源码剖析》,p142
// list 不能使用 STL 算法 sort(),必须使用自己的 sort() member function,
// 因为 STL 算法 sort() 只接受 RamdonAccessIterator
// 本函式采用 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]);
}
很显然上述代码并非快速排序,而是归并排序。快速排序代码如下:
void QuickSort(int array[], int low, int high) {
int i = low;
int j = high;
int key = array[i];
if (low < high) {
while (i < j) {
while (i < j && array[j] >= key) {
j--;
}
if (i < j) {
array[i] = array[j];
}
while (i < j && array[i] <= key) {
i++;
}
if (i < j) {
array[j] = array[i];
}
}
array[i] = key;
QuickSort(array, low, i - 1);
QuickSort(array, i + 1, high);
}
}
sizeof
// 《STL源码剖析》,p146
static size_t buffer_size() { return __deque_buf_size(Bufsize, sizeof(T); }
- sizeof 运算符返回一条表达式或一个类型名字所占的字节数。
- sizeof 运算符满足右结合律,其所得的值是一个 size_t 类型的常量表达式。
- C++11 新标准允许我们使用作用域来获取类成员的大小。
- 对 char 或者类型为 char 的表达式执行 sizeof 运算,结果得1.
- 对引用类型执行 sizeof 运算得到被引用对象所占空间的大小。
- 对指针执行 sizeof 运算得到指针本身所占空间的大小。
- 对解引用指针执行 sizeof 运算得到指针指向的对象所占空间的大小,指针不需有效。2
size_t
// 《STL源码剖析》,p151
size_type size() const { return size_type(-1); }
在这里 size_type 等于 size_t,size_t 是一种机器相关的无符号类型3,所以将 -1 强制转换为无符号类型会得到最大的无符号数。
__STL_UNWIND( … )
// 《STL源码剖析》,p156
__STL_TRY {
construct(finish.cur, t_copy); // 针对标的元素设值
finish.set_node(finish.node + 1); // 改变 finish,令其指向新节点
finish.cur = finish.first; // 设定 finish 的状态
}
__STL_UNWIND(deallocate_node(*(finish.node + 1)));
其中 __STL_TRY 和 __STL_UNWIND 定义如下所示:
// "stl_config.h"
# ifdef __STL_USE_EXCEPTIONS
# define __STL_TRY try
# define __STL_CATCH_ALL catch(...)
# define __STL_THROW(x) throw x
# define __STL_RETHROW throw
# define __STL_NOTHROW throw()
# define __STL_UNWIND(action) catch(...) { action; throw; }
# else
# define __STL_TRY
# define __STL_CATCH_ALL if (false)
# define __STL_THROW(x)
# define __STL_RETHROW
# define __STL_NOTHROW
# define __STL_UNWIND(action)
# endif
约束模板友元函数
// 《STL源码剖析》,p167
template <class T, class Sequence = deque<T> >
class stack {
// 以㆘的 __STL_NULL_TMPL_ARGS 会开展为 <>,见 1.9.1 节
friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
...
};
声明中的 <> 指出这是模板具体化,<> 可以为空,因为可以从函数参数中推断出模板参数的类型。4