第一章、STL概论与版本简介
一、临时对象的产生与运用。P36
这里的临时对象,指的是一种无名对象(unnamed subjects),如果它们的产生不在程序员的预料之下,往往造成效率的负担,但有时刻意制造临时对象会让程序干净清爽。刻意制造临时对象的方法是,在型别名称后直接加一对小括号,并可指定初值。例如Shape(3,5)或者int(8),其意义相当于调用相应的构造函数且不指定对象名称。STL常将此技巧应用在仿函数(functor)与算法的搭配上。
例如:
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
template<typename T>
class print
{
public:
void operator() (const T& elem) //operator() 重载
{
cout << elem << " " ;
}
};
int main()
{
int ia[6] = {0,1,2,3,4,5};
vector<int> iv(ia, ia+6);
//print<int>()是一个临时对象,不是函数调用操作
for_each(iv.begin(), iv.end(), print<int>());
return 0;
}
最后一行产生的便是"class template"的具现体print<int>的一个临时对象。
PS:赋值运算符用于同类对象间的相互赋值。赋值运算符只能被重载为类的非静态成员函数,不能重载为友元函数和普通函数。重载赋值运算符函数必须是public的,否则会编译错误,因为用户定义了重载赋值运算符函数,编译器就不会提供默认的。在类中重载的赋值运算符函数不能被继承。
通常情况下编译器提供的默认重载赋值运算符函数能够解决对象间赋值的问题,但是当类中含有指针数据成员时,容易引起指针悬挂的问题,所以这种情况下有必要进行赋值运算符重载。
如果针对某个Class进行operator()重载,它就成了一个仿函数。
第二章、空间适配器
一、STL内存管理中的free_lists:
次层配置(sub-allocation):每次配置一块大内存,并维护对应的自由链表(free_list)。下次若再有相同大小的内存需求,就直接从free_lists中拔出。如果客端释还小额区块,就由配置其回收到free_list中。为方便管理,SGI第二级适配器会主动将任何小额区块的内存需求量上调至8的倍数(例如客端要求30bytes,就自动调整为32bytes)。并维护16个free_lists。
PS:STL中利用位运算上调为8的倍数:
union obj
{
union obj* free_list_link;
char client_data[1]; /* The Client see this. */
};
enum {__ALIGN = 8}; //小型区块的上调边界
size_t ROUND_UP(size_t bytes)
{
return (((bytes) + __ALIGN - 1) & ~(__ALIGN - 1));
}
free_list节点结构如下:
union obj
{
union obj* free_list_link;
char client_data[1]; /* The Client see this. */
};
一个自由链表(free_list)在同一时刻,具备且仅具备如下功能之一:
1、作为一个自由链表指针,指向下一个自由链表
2、自身作为一块可用内存,供用户使用
由于如上用途不可能同时出现,故将obj定义为union,将free_list_link和client_data共享同一块内存来节省内存。
一旦这个自由链表块被分配给用户了,那么它就从自由链表中被移除了,不再被认为是一个自由链表块(由union的语义,从此它就是一块普通的,分配给用户的内存,直到被用户释放,它才会被再次加入自由链表中)。
free_list从0开始算起,只需要做一次位运算来决定使用第n号free_list:
size_t FREELIST_INDEX(size_t bytes)
{
return (((bytes) + __ALIGN - 1) / __ALIGN - 1);
}