effictive c++条款10认为如果有必要重写operator new,就必须同样的要重写operator delete,这里有个疑问,该什么时候需要重写operator new 呢?
举例说明,加入有如下的类:
class A
{
private:
class B *p;
};
在代码 A *p = new A(); 时,会调用系统内置的operator new 函数,operator new函数会分配一段内存,这个内存包括2部分: 方便delete的标识信息 + A实际内存。
因为delete要想合理的删除new分配的内存,new函数必须要告诉delete函数要删除内存的位置和大小等信息,这样以来,一个很小的类A在new的时候就会多次一部分标志信息,在内存比较紧张的情况下,又需要反复多次的new A,这个标志信息就会占用很多内存,就有必要考虑重写operator new函数。
具体实现就是在operator new函数中以链表的形式一次性分配很多内存块,每次new的时候都把当前未使用的分配出来,返回当前operator new 的结果。
代码如下:
#include <iostream>
class airplanerep
{
public:
airplanerep(){}
~airplanerep(){}
};
class airplane
{
public:
airplane(): rep(0)
{
rep = new airplanerep();
}
public:
static void* operator new(size_t size);
static void operator delete(void* deadobject, size_t size);
private:
union
{
airplanerep *rep;
airplane *next;
};
static const int block_size;
static airplane *headoffreelist;
};
airplane* airplane::headoffreelist = 0;
const int airplane::block_size = 512;
void* airplane::operator new(size_t size)
{
if (size != sizeof(airplane))
return ::operator new(size);
airplane *p = headoffreelist; // p 指向自由链表的开头
if (p)
headoffreelist = p->next;
else
{
// 自由链表为空,则分配一个大的内存块,
// 可以容纳block_size个airplane对象
airplane *new_block = static_cast<airplane*>(::operator new(block_size * sizeof(airplane)));
//将每个小内存块连接成一个新的自由链表
//跳过第0个元素,因为它要被返回给operator new 的调用者
for (int i = 1; i < block_size; ++i)
new_block[i].next = &new_block[i+1];
//用空指针结束链表
new_block[block_size - 1].next = 0;
// p设为表的头部,headoffreelist指向的内存紧跟其后
p = new_block;
headoffreelist = &new_block[1];
}
return p;
}
void airplane::operator delete(void* deadobject, size_t size)
{
if (0 == deadobject)
return;
if (size != sizeof(airplane))
{
return ::operator delete(deadobject);
}
airplane * carcass = static_cast<airplane*>(deadobject);
carcass->next = headoffreelist;
headoffreelist = carcass;
}
class A
{
public:
void show()const {std::cout << i << std::endl;}
private:
int i;
};
int main()
{
// 改进后的operator new函数之后,在多次new的时候,可以从当前链表中获取需要的内存,不用多次的申请内存和额外的信息内存
//
airplane *my_airplane_one = new airplane;
delete my_airplane_one;
// A *p = new A[2];
// delete []p;
return 0;
}
在课后的poll线程池就让代码更加清晰,同时使用模版,不多说,大概都一样。
代码:
#include <iostream>
class airplanerep
{
public:
airplanerep(std::string name_val = "", size_t size_val = 0): name(name_val), size(size_val){}
~airplanerep(){}
public:
std::string get_name()const {return name;}
size_t get_size()const { return size;}
private:
std::string name;
size_t size;
};
template< typename obj_type>
class poll
{
public:
poll(){}
public:
void* alloc(size_t size);
void free(void* p, size_t size);
private:
union data_unit
{
obj_type *ref;
data_unit *next;
};
data_unit * headoffreelist;
static size_t block_size;
};
template <typename obj_type>
size_t poll<obj_type>::block_size = 20;
template <typename obj_type>
void* poll<obj_type>::alloc(size_t size)
{
if (size != sizeof(data_unit))
return ::operator new(size);
data_unit *p = headoffreelist; // p 指向自由链表的开头
if (p)
headoffreelist = p->next;
else
{
// 自由链表为空,则分配一个大的内存块,
// 可以容纳block_size个airplane对象
data_unit *new_block = static_cast<data_unit*>(::operator new(block_size * sizeof(data_unit)));
//将每个小内存块连接成一个新的自由链表
//跳过第0个元素,因为它要被返回给operator new 的调用者
for (size_t i = 1; i < block_size; ++i)
new_block[i].next = &new_block[i + 1];
//用空指针结束链表
new_block[size - 1].next = 0;
// p设为表的头部,headoffreelist指向的内存紧跟其后
p = new_block;
headoffreelist = &new_block[1];
}
return p;
}
template <typename obj_type>
void poll<obj_type>::free(void* p, size_t size)
{
if (0 == p)
return;
if (size != sizeof(p))
{
return ::operator delete(p);
}
data_unit * carcass = static_cast<data_unit*>(p);
carcass->next = headoffreelist;
headoffreelist = carcass;
}
class airplane
{
public:
airplane(): rep(0)
{
rep = new airplanerep("my_airplane_name", 100);
}
public:
static void* operator new(size_t size);
static void operator delete(void* p, size_t size);
private:
airplanerep * rep;
static poll<airplane> mem_poll;
};
poll<airplane> airplane::mem_poll;
void* airplane::operator new(size_t size)
{
return mem_poll.alloc(size);
}
void airplane::operator delete(void* p, size_t size)
{
mem_poll.free(static_cast<airplane*>(p), size);
}
int main()
{
airplane* p = new airplane();
delete p;
return 0;
}
希望我再看的时候能过看懂!!