本文适用于对效率要求非常高、并且修改频率远大于查找频率的情况。按需申请空间,高效利用碎片化空间并节约掉反复申请、拷贝、释放带来的时间浪费。
以string类的重载+=运算符为例:
new分为3种,我们平常使用的也是最常见的是new operator。
对于charp=new char[N];
它的本质是 在堆中分配一块内存。
而假如new一个对象,如 class T p=new class T; 它在分配内存之后还会调用构造函数来进行初始化。
可见它并没有realloc的功能。我们需要自行使两段空间链接起来。
那么如何用new实现在旧空间后申请新空间呢?可以考虑使用链表。
首先,定义一个content类,内部存储字符数组指针下一个内容块的指针。在TString类中,定义一个头指针。
struct content
{
char* con;
content* next;
};
class TString {
private:
content* head;
int len;
public:
TString& operator +=(const char *s2);
}
在链接链表时,每一个新内容块都要做两次申请,申请content对象建立链表以便索引,申请数组以存储。
TString& TString ::operator +=(const char* s2)
{
int len2 = strlen(s2);
content* p = head;
while (1) {
if ((*p).next)
p = (*p).next;
else
break;
}
if((*p).con)
p = (*p).next = (content*) new content;
(*p).con = new(nothrow) char[len2 + 1];
if ((*p).con == NULL)exit(0);
(*p).next = NULL;
memcpy((*p).con, s2, len2 + 1);
len += len2;
return *this;
}
内存示意图
在每次累加0.1~0.2MB至100MB的测试中,这种方法所需时间仅为普通+=的10%。Crazy!