设为首页 加入收藏

TOP

转C++内存管理(五)
2017-06-08 10:22:35 】 浏览:433
Tags:内存 管理
nc ofclass A” << endl; } }; void Test(void){ A *p; { A a; p = &a;// 注意 a 的生命期 } p->Func();// p是“野指针” }

函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

有了malloc/free为什么还要new/delete

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。

对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。

因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,见示例:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22class Obj{ public :   Obj(void){cout << “Initialization” << endl; }   ~Obj(void){cout << “Destroy” << endl; }   void Initialize(void){cout << “Initialization” << endl; }   void Destroy(void){cout << “Destroy” << endl; } }; void UseMallocFree(void){ Obj *a = (obj *)malloc(sizeof(obj));// 申请动态内存 a->Initialize();// 初始化 //… a->Destroy();// 清除工作 free(a);// 释放内存 } void UseNewDelete(void){ Obj *a =new Obj;// 申请动态内存并且初始化 //… delete a;// 清除并且释放内存 }

类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数UseNewDelete则简单得多。

所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。

既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。

如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,结果也会导致程序出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。

内存耗尽怎么办

如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理“内存耗尽”问题。

(1). 判断指针是否为NULL,如果是则马上用return语句终止本函数。例如:

1 2 3 4 5 6 void Func(void){ A *a =new A; if(a == NULL) return; … }

(2). 判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。例如:

1 2 3 4 5 6 7 8 9void Func(void){ A *a =new A; if(a == NULL){ cout << “Memory Exhausted” << endl; exit(1); } … }

(3). 为new和malloc设置异常处理函数。例如Visual C++可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new相同的异常处理函数。详细内容请参考C++使用手册。

上述 (1)、(2) 方式使用最普遍。如果一个函数内有多处需要申请动态内存,那么方式 (1) 就显得力不从心(释放内存很麻烦),应该用方式 (2) 来处理。

很多人不忍心用exit(1),问:“不编写出错处理程序,让操作系统自己解决行不行?”

不行。如果发生“内存耗尽”这样的事情,一般说来应用程序已经无药可救。如果不用exit(1)把坏程序杀死,它可能会害死操作系统。道理如同:如果不把歹徒击毙,歹徒在老死之前会犯下更多的罪。

有一个很重要的现象要告诉大家。对于32位以上的应用程序而言,无论怎样使用malloc与new,几乎不可能导致“内存耗尽”。对于32位以上的应用程序,“内存耗尽”错误处理程序毫无用处。这下可把Unix和Windows程序员们乐坏了:反正错误处理程序不起作用,我就不写了,省了很多麻烦。

必须强调:不加错误处理将导致程序的质量很差,千万不可因小失大。

1 2 3 4 5 6 7 8 9void main(void){ float *p = NULL; while(TRUE){ p =newfloat[1000000]; cout << “eat memory” << endl; if(p==NULL) exit(1); } }

malloc/free的使用要点

函数malloc的原型如下:

1void *malloc(size_t size);

用malloc申请一块长度为length的整数类型的内存,程序如下:

1int *p = (int *)malloc(sizeof(int) * length);

我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。

* malloc返回值的类型是void*,所以在调用malloc时要显式地进行类型转换,将void *转换成所需要的指针类型。

* malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。我们通常记不住int,float等数据类型的变量的确切字节数。例如int变量在16位系统下是2个字节,在32位下是4个字节;而float变量在16位系统下是4个字节,在32位下也是4个字节。最好用以下程序作一次测试:

1 2 3 4 5 6 7 8 cout < cout < cout < cout < cout < cout < cout < cout <

在malloc的“()”中使用sizeof运算符是良好的风格,但要当心有时我们会昏了头,写出p = malloc(sizeof(p))这样的程序来。

函数free的原型如下:

1voidfree(void * memblock );

为什么f

首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇演练:创建和使用动态链接库 (C++) 下一篇Effective c++ 学习笔记(二)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目