锁定老帖子 主题:其实你应该这样学C++(连载)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (8)
|
|
---|---|
作者 | 正文 |
发表时间:2012-11-12
第10讲 内存管理
在本章节,我们主要讨论关于内存的管理问题,这一部分内容,属于编程语言里面的高级内容了,它是每个想成为C++高手必须掌握的内容之一。也许现在的你听着会有点云里雾里的感觉,但是不要担心,当你回过头来再仔细回味的时候,你会发现它是多么的重要。下面我们就具体来谈谈关于C++程序设计当中的内存管理问题。 10.1 时间和空间 在计算机的程序设计当中,有两种重要的资源:时间和空间。 所谓的时间就是指执行一个指令的运行时间,有时候我们也称其为执行效率,时间短,我们认为其执行效率相对比较高;时间长,我们认为其执行效率相对比较低。 所谓的空间则是指保存数据和程序的内存。 在C++语言里面内存管理几乎无处不在,因而如果要想成为一个C++高手,优化程序、掌握其内存管理是不可或缺的一部分。 但是,这里值得注意的是:内存管理就好比是锦上添花的一件事情,它的第一个阶段是你正确的写出符合你自己需求的程序,因为一个程序就算其内存管理做的再好,如果不能够解决你想解决的问题,达不到预期的效果,那也是徒劳,即要做对事情;其次才是第二个阶段——提高其工作效率。 |
|
返回顶楼 | |
发表时间:2012-11-12
10.2 内存分配方式
在C++当中,内存的分配方式主要有全局/静态存储区、堆、栈、自由存储区以及常量存储区等五个部分。 全局/静态存储区是指全局变量和静态变量处于同一个内存当中,它们共同占用一个内存区。 堆就是指那些由new分配的内存块,一般一个new就会相应的对应着一个delete。同时需要注意的是:需要使用相同形式的new和delete,否则很容易发生错误,具体的在下面的部分会进行详细的讲解。 栈内存的分配运算内置于处理器的指令集当中,因而处理的效率很高,唯一不足的就是分配的内存的容量有限。 自由存储区就是指由malloc等来进行分配的存储区,一般它需要使用free来进行释放,和堆的相同之处在于它们也需要成对的出现,同时它也是C++继承的C语言的一个部分。如果内存以malloc进行配置,而没有使用free进行释放,就会产生内存泄露的问题。 常量存储区是指存放常量的一块存储区,其最大的特点在于不允许进行修改。 |
|
返回顶楼 | |
发表时间:2012-11-12
10.3 常见内存问题解析
1.一个new对应着一个delete,同时要求它们的形式相同。 在前面我以及提及到,当出现一个new的时候,就需要有一个相同形式的delete与之配对出现。下面我们具体的看它们的使用: int *p = new int[8]; …… delete []p; 如果new的对象是有多个构造函数,其new的形式也有多种样式,例如: class M { public: M(void);//没有参数的构造函数 M(int a);//带有参数的构造函数 …… }; void N(void) { M *x=new M; M *y=new M(2);//初始值为2,如果是数组不可以这样使用 …… delete x; delete y; } 在这里需要注意的是,当我们使用new创建对象数组的时候,仅能使用对象的无参数构造。同时使用的形式必须相同,例如: int *p = new int[10]; …… delete p; 也许你会觉得上面的这两行简短的代码是没有错误的,但是,当你试着运行的时候,你发现,你错了。也许你会纳闷,为什么呢?我保证到了new与delete的成对出现了啊,那这个到底是怎么回事呢?其实答案很简单,就是虽然你注意到了new与delete的成对出现,但是,你没有考虑到其形式必须相同。下面我们详细的进行剖析一下发生错误的原因: 当我们使用new的时候,首先内存会被配置,其次是constructors被调用,而且有可能不止一个被调用。而当我们最后使用delete进行释放内存的时候,就遇到了一个比较棘手的问题了,到底有多少个对象需要被删除?也就是说,即将被删除的那个指针,所指向的是单一对象还是一个数组?而这恰好是delete所无法自动获取的,在没有告诉它的情况下,就会发生错误。 例如: int *p 1= new int; int *p2 = new int[8]; …… delete p1; delete []p2; 在上面的例子中,对于指针p1,我们新建了一个单一的对象,在其后进行内存释放的时候,使用了delete 对其进行了内存释放;对于指针p2,我们则新建了一个对象数组,那么在进行内存释放的时候,我们使用了“delete []p2”来释放整个数组,如果我们不去使用“[]”,而是单独的使用和释放指针p1相同的方式进行释放,将会因为delete无法知道释放多少对象而发生错误。 通过上面的这个例子,我们可以总结如下:当你在new的时候没有使用“[]”,那么在你进行delete的时候也不需要使用“[]”;如果当你在new的时候使用了“[]”,那么在你进行delete的时候,你也需要使用“[]”,切记! 2.malloc与free也需要成对出现,同时其与new与delete之间不可完全替代。 C++语言继承了许多C语言的函数,malloc与free就是其中一个。而与之相对应的C++里面即是前面所将的new与delete。所不同的是,malloc与free是标准库函数,而new与delete是运算符。也许你之前还在想,为什么有了malloc与free还需要new与delete呢?现在应该明白了吧。我们可以看这样的一个简单的例子来进一步的加深理解。 class M { public : M(void) { cout << “Initi” << endl; } ~M(void) { cout << “Dest” << endl; } void Initi (void){ cout << “Initi” << endl; } void Dest (void){ cout << “Dest” << endl; } }; void MFree (void) { M *p = (M *)malloc(sizeof(M)); //申请内存空间 p->Init (); // 初始化 …… p->Dest ();//清除 free(p); //释放内存 } void NDelete(void) { M *p = new M; // 申请动态内存并且初始化 //... delete p; // 清除并且释放内存 } 在上面的这个例子当中,我们使用了类M的函数Initi来模拟了构造函数的功能,同时使用了Dest模拟了析构函数的功能。但是,我们可以看出在函数MFree当中由于malloc与free不能够执行构造函数和析构函数,因而必须使用成员函数来完成初始化和清除工作,在这一点上new与delete要方便很多。也许你会疑惑了,既然new与delete能够实现其相同的功能,并且相对的简单许多,那么为什么我们不可以使用new与delete来代替malloc与free呢?答案就是:C++程序经常要调用C函数,而C程序只能用malloc与free管理动态内存。因而不可以替代,同时malloc与free和new与delete也不可以进行混搭使用,即malloc与delete、new与free等都是不正确的。 3.如何判断内存是否分配成功。 很多初学者,很容易犯的一个错误就是在内存还没有分配成功的情况下就进行其他的相关工作。那么,如何判断内存是否分配成功呢?常用的办法主要有:在使用内存之前检查指针是否为空(这里为了叙述方便假设指针为p),如果指针p是函数的参数,那么在函数的入口处可以选择使用assert(p!=NULL)对其进行检查。 4.内存泄露。 很多初学者在起初,忘记进行内存的释放,从而造成内存的泄露。在刚开始内存比较充足的情况下也许不会立刻发生错误,但是随着不断的调用程序,系统的内存在逐渐的减少,内存不断的丢失(有时候也称空内存),最终因为内存耗尽而发生错误。 因而我们在使用malloc与free或者new与delete进行动态内存的申请的时候,一定要注意申请与释放要配对,否则就会发生像上面所描述的内存泄露的现象,最终导致错误发生。 然而,当你的代码中到处充满了new操作、delete操作以及指针运算的话,你将会在某个地方搞晕了头,从而导致内存泄漏、指针引用错误,以及其他诸如此类的问题出现。 这些与你如何小心地对待内存分配工作其实完全没有关系:代码的复杂性最终总是会超过你能够付出的时间和努力。在此基础上于是随后产生了一些成功的技巧,它们依赖于将内存分配与重新分配工作隐藏在易于管理的类型之后。 标准容器就是一个这样的优秀例子。它们不是通过写程序的人,而是自己为元素管理内存,从而避免了产生不好的结果。 5.如果在申请内存空间的时候发现,内存不足怎么处理? 当我们在申请动态内存的时候,如果找不到足够大的内存空间,那么此时new或者malloc将会返回一个空指针,从而宣布了内存空间申请的失败。通常在遇到这样的情况发生我们做如下的处理: (1)判断指针是否为空指针,如果是则立即使用return 语句终止本函数的执行。 例如: void Func(void) { M *p = new M; if(p == NULL) { return; } …… } (2)判断指针是否为空指针,如果是则立即使用exit(1)终止整个程序的运行。 例如: void Func(void) { M *p = new M; if(p== NULL) { cout << “内存耗尽!” << endl; exit(1); } …… } |
|
返回顶楼 | |
发表时间:2012-11-12
10.4 小结
本章主要讲述了C++内存管理的一些初步的概念和常见的问题解析,主要为读者打开一个学习的思路。这一部分内容,属于C++里面比较深奥的一部分了,读者需要在掌握其他内容的基础上,深入研究,同时需要参看其他的一些相关的专门资料,在这里不作为重点内容,有兴趣的读者可以自行阅读。 |
|
返回顶楼 | |
发表时间:2012-11-12
其实你完全不应该这样学习c++
|
|
返回顶楼 | |
发表时间:2012-12-14
你这是灌水还是在干啥。
|
|
返回顶楼 | |
发表时间:2012-12-17
其实你不该学C++的
|
|
返回顶楼 | |
发表时间:2012-12-18
貌似楼主连载的这本书是一本入门书籍哦~~ 看起来貌似不错吧。
我觉得在入门书上加上预处理和链接过程的讲解是很有必要的,有些工作两年的人竟然不了解链接过程。。。。 |
|
返回顶楼 | |
发表时间:2012-12-18
感谢作者的分享
|
|
返回顶楼 | |
发表时间:2013-03-16
不错,学习了,C++很强大哦。
|
|
返回顶楼 | |