假设遇到这样一个问题,有一个部落,存在若干个成员,每个成员有两个属性分别是年龄和地位等级。在程序中为构造这样一个部落对象,会想到嵌套结构体的方式。已知部落成员不是固定的,我们对成员这个对象采用指针来表示。
那么现在就有两个结构体,第二个结构体嵌套第一个结构体,要如何进行动态内存分配和管理呢?本文就是对该类结构体的内存管理进行的实践。
首先构造第一个结构体,假设内结构体INSIDE,属性a和b,那么结构体代码如下:
typedef struct _stuInside
{
int a;
int b;
} INSIDE;
然后构造第二个结构体,假设为外结构体OUTSIDE,由于成员数量是动态的,因此我们在该结构体中构造一个变量代替数目,然后用内结构体指针表示元素集合,结构体代码如下:
typedef struct _stuOutside
{
int count;
INSIDE *element;
} OUTSIDE;
数据结构构造完成,接下来为了使用这一个数据结构我们需要创建其对象,但是如上代码所示,这个结构体是没有给成员分配好内存的,也就是需要为结构体动态分配内存。大致归纳下有以下几种场景:
1、一个部落一个成员
2、一个部落多个成员
3、多个部落一个成员
4、多个部落多个成员
抽象到代码,就是
OUTSIDE *p = new OUTSIDE;
OUTSIDE *p = new (n) OUTSIDE;
OUTSIDE *p = new OUTSIDE[n];
OUTSIDE *p = new (n) OUTSIDE[n];
从上述代码可以看到我选择的是new的方式分配内存空间,简单起来没有问题,但是仔细想下,这样是有问题的,因为外结构体的第二个成员是指针,new分配的给该成员的内存空间大小是4个字节。
要想解决这个问题,我选择的方法是为该结构体重载new操作符,为什么去重载而不是直接在使用者代码中分配呢,我的理由是既然这个数据结构是抽象的通用结构,那么被调用是很频繁的,预期将复杂的内存分配给调用者实现,还不如直接封装到结构体自身,这样可以减少调用者对内存管理的负担。
从上述代码也可以看出来,这里需要重载的new操作符有,operator new、operator new(n)、operator new[]、operator new(n)[],在标准C++中new操作符实际是个函数,其形式是void * operator new(size_t size),对这部分知识就不介绍了,网上很容易找到资料。
我的重载代码:
static void * operator new(size_t size)
{
// 用标准new处理size错误,含size=0
if (size != sizeof(struct _stuOutside))
{
return ::operator new(size);
}
while (1) // 无限循环处理
{
void *p = malloc(size);
if (p != 0)
{
struct _stuOutside *pp = (struct _stuOutside *)p;
pp->count = 1;
pp->element = (INSIDE *)malloc(sizeof(INSIDE));
return p; // 分配成功后返回指针
}
new_handler curhandler = set_new_handler(0);
set_new_handler(curhandler);
if (curhandler != 0)
(*curhandler)();
else
throw std::bad_alloc();
}
}
static void * operator new[] (size_t size)