您的位置:首页 > 编程语言 > C语言/C++

C++内存动态分配及管理

2010-12-11 22:00 465 查看
                                                         C++内存动态分配及管理

 

     内存动态分配与管理是C++灵活性的一种体现,本贴探讨C++中内存的动态分配与管理。

 
一、简单的内存分配
在C++中,引入了一对新的操作符new/delete来动态分配和释放内存。虽然旧的malloc/free仍然有效,但强烈建议不再使用它们。因为new/delete做了一些“我们不知道”的事情。比如有一个类A,我们执行下面的操作:
A* pNew = new A();
delete pNew;

C++中总是先分配内存,然后调用A的构造函数。那么对应的操作可能是下面的样子:
A* pNew = malloc(sizeof(A));       //分配一片内存.
pNew->A();                         //调用构造函数.
…
pNew->~A();                        //调用析构函数.
free(pNew);                        //释放内存.

现在我们知道:malloc/free只是简单的执行内存分配,而new/delete在分配内存的同时,还在这片内存上执行了对象的构造或析构。
 
二、多维数组的动态分配
有时候我们需要动态分配一个多维数组——比如创建一幅游戏地图。那么我们可以通过动态创建来完成。多维数组的分配有多种方式,如下:
1>    直接分配:
我们用二维数组为例,这个比较容易,如下:
int (*pArr)[4] = new int[3][4];            //alloc pArr[3][4].

这样就创建了一个三行四列的二维数组,释放操作如下:
delete [] pArr;                            //delete it.

也可以像下面操作,比较直观:
typedef int(pARRAY)[4];
pARRAY* ppArr = new pARRAY[3];

这样也创建了一个三行四列的二维数组,释放操作和上面一样。三维、多维的操作和二维的类似。
 
2>    多次分配:
我们也可以通过多重分配来模拟:
int **ppArr = new int*[3];
for(int i=0; i!=3; ++i)
{
ppArr[i] = new int[4];
}

这样也创建了一个三行四列的二维数组,释放操作如下:
for(int i=0; i!=3; ++i)
{
 delete [] ppArr[i];
}

delete [] ppArr;

可以看出,创建、释放操作比第一种方法麻烦了不少。其余的操作基本一样。所以我们最好用第一种方式来动态创建多维数组。
 
三、几种new方法:
1>    plain new:
这种普通的new方法我们只能通过异常检测来判断内存分配是否成功,而不是通过检测new返回的指针是否为NULL。因为C++标准规定:“plain new在分配失败后抛出std::bad_alloc异常,而不是返回NULL。”示例如下:
try
{
int* pInteger = new int(12);
}
catch(std::bad_alloc& err)
{
    //Alloc FAILED!do something…
}

像下面的检测操作是无用的:
if(pInteger == NULL)
{
    //Alloc FAILED!do something…
}

 
 
2>    nothrow new:
我们可以通过nothrow来分配一片内存,这样如果分配失败,则返回NULL而不是抛出std::bad_alloc异常:
int* pInteger = new(nothrow) int(12);
if(pInteger == NULL)
{
//Alloc FAILED!do something…
}

我们可以知道,哑元nothrow是C++中全局的一个nothrow_t的const对象。
 
3>    placement new:
如果我们频繁动态创建/释放对象,那么我们可能会用到placement new方法,这种方法通过指定一片已动态分配的内存,来在上面执行对象创建操作,而不会重新分配内存。如下:
int* pInteger = new int(12);              //*pInteger = 12.
pInteger = new(pInteger) int(23);         //*pInteger = 23.

placement new操作只是简单的在pInterger所指向的内存上执行对象的构造。需要注意的是:placement new分配的内存需要我们自己显式调用析构函数,如:pObj->~ClassName();。
 
这种方法很有用,比如在一个太空游戏中要动态创建/释放很多的敌机、飞船,那么我们会用到placement new,将分配后要释放的内存简单的放到我们管理的内存池中,然后在下次有对象创建时简单的执行placement new即可。比如我们的内存池为CMemoryPool:
CMemoryPool craftPool;                       //飞船池.

如果我们要创建飞船,那么在需要创建时只需在内存池中查询,如果有可用的内存,则返回一片可用内存并在上面执行placement构造,否则只是创建一份即可。
CCraft* pNewCraft = 0;
if(pNewCraft = craftPool.Query())
{
pNewCraft = new(pNewCraft) CCraft;
}
else
{
pNewCraft = new CCraft;               //内存池中没有可用内存.
}

//do something…

在飞船被击毁时,只需将它解除,然后添加到内存池即可:
pNewCraft->~CCraft();             //显式调用析构函数.
craftPool.AddMemory(pNewCraft);      //飞船被“释放”,不可用.

这样就避免了频繁的创建/释放操作使堆千疮百孔了。综上我们简单介绍了C++中动态分配内存的管理等问题。
 
 
                                                                           --By:YaFengZhang
                                                                           --Date:2010.12.11
                                                                           --Blog:http://blog.csdn.net/ZhangYafengCPP
 
 
 
 
 
 
 
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ delete null 游戏 c 2010