[学习C++]内存管理

合集下载

使用C语言技术进行内存管理的方法

使用C语言技术进行内存管理的方法

使用C语言技术进行内存管理的方法使用C语言进行内存管理的方法在编程中,内存管理是一个非常重要的问题。

合理地管理内存可以提高程序的性能和效率,避免内存泄漏和内存溢出等问题。

本文将介绍一些使用C语言技术进行内存管理的方法。

1. 动态内存分配动态内存分配是C语言中常用的内存管理技术之一。

通过动态内存分配,我们可以在程序运行时根据需要动态地分配和释放内存。

C语言提供了几个函数来进行动态内存分配,如malloc、calloc和realloc。

其中,malloc函数用于分配指定大小的内存空间,calloc函数用于分配指定数量的相同大小的内存空间,并将其初始化为0,realloc函数用于重新分配已分配内存的大小。

2. 内存释放动态分配的内存在使用完毕后必须及时释放,以免造成内存泄漏。

C语言中使用free函数来释放动态分配的内存。

当不再需要使用某块内存时,应该调用free函数将其释放,以便系统可以重新利用该内存。

3. 内存回收除了手动释放内存外,C语言还提供了一种自动回收内存的机制,即垃圾回收。

垃圾回收是一种自动管理内存的技术,它会自动检测和回收不再使用的内存,避免程序员手动释放内存的繁琐工作。

C语言中并没有内置的垃圾回收机制,但可以使用第三方库或框架来实现自动内存回收。

4. 内存池内存池是一种用于管理内存的数据结构,它可以提高内存分配和释放的效率。

内存池将一块较大的内存空间划分为多个小块,每次分配和释放内存时,只需要在内存池中进行操作,而不需要频繁地向系统申请和释放内存。

内存池可以减少内存碎片和系统调用的次数,提高程序的性能。

5. 内存对齐内存对齐是一种对齐内存访问的规范,可以提高内存访问的效率。

在C语言中,结构体和数组的内存对齐是由编译器自动完成的,但对于动态分配的内存,我们需要手动进行内存对齐。

可以使用C语言的一些特性来实现内存对齐,如使用宏定义来指定对齐方式,使用特定的数据类型来保证内存对齐。

6. 内存检测工具为了帮助程序员检测和调试内存相关的问题,C语言提供了一些内存检测工具,如valgrind和GDB。

C语言内存使用详解

C语言内存使用详解

C语言内存使用详解C语言是一种低级语言,开发者可以直接控制内存使用。

了解C语言内存使用的机制和技巧对于编写高效、安全和可靠的程序至关重要。

本文将详细介绍C语言内存使用的知识和技术,并提供一些实用的建议。

在C语言中,内存是以字节为单位进行管理的,通常将内存分为栈和堆两种。

栈是一种自动分配和自动释放内存的数据结构。

它的特点是后进先出(LIFO),即最后分配的内存最先释放。

栈主要用于存储局部变量、函数参数和函数调用的上下文信息。

在函数调用结束后,分配给局部变量的内存会自动释放。

堆是一种动态分配内存的数据结构,程序员可以手动分配和释放内存。

堆的管理需要调用系统提供的函数,如malloc(和free(。

堆主要用于存储动态分配的数据,如数组、结构体和指针。

程序员需要手动管理堆内存,确保及时释放不再使用的内存,否则会造成内存泄漏。

为了更好地使用内存,提高程序的性能和可靠性,下面是一些C语言内存使用的技巧和注意事项:1.使用局部变量:局部变量是保存在栈上的,它们的生命周期与函数的调用关系密切相关。

局部变量不仅可以节约内存,还可以提高程序的执行效率。

2.合理分配静态变量和全局变量:静态变量和全局变量在程序执行过程中一直存在,它们的生命周期不受函数调用的影响。

过多的静态变量和全局变量会占用大量的内存,影响程序的性能。

3. 动态分配内存时要检查返回值:在调用malloc(等动态分配内存的函数时,要检查返回值是否为NULL。

如果返回值为NULL,表示没有足够的内存可用。

处理内存分配失败的情况至关重要,可以提前终止程序或采取其他恰当的措施。

4. 及时释放不再使用的内存:动态分配的内存在不再使用时要及时释放,以避免内存泄漏。

使用free(函数将内存返回给系统,以供其他程序使用。

5.防止指针错误:指针是C语言中非常重要的概念,但也容易出现指针错误,如空指针引用、越界访问等。

使用指针时要特别小心,确保指针正确地指向有效的内存区域。

C语言技术中的内存管理和垃圾回收技巧

C语言技术中的内存管理和垃圾回收技巧

C语言技术中的内存管理和垃圾回收技巧在计算机编程领域中,内存管理和垃圾回收是至关重要的技术。

C语言作为一种高效的编程语言,对于内存管理和垃圾回收的实现有着独特的方法和技巧。

本文将探讨C语言中的一些内存管理和垃圾回收技巧,以帮助开发人员更好地利用和管理内存资源。

一、静态内存分配和动态内存分配在C语言中,内存可以通过静态内存分配和动态内存分配两种方式进行管理。

静态内存分配是指在编译时确定内存的分配和释放,而动态内存分配则是在程序运行时根据需要进行内存的分配和释放。

静态内存分配适用于那些在程序整个生命周期内都需要存在的变量和数据结构。

这些变量和数据结构在编译时就被分配好了内存空间,并在程序运行期间一直存在。

静态内存分配的好处是速度快,但是缺点是浪费内存资源,因为这些内存空间可能在某些时候并不被使用。

动态内存分配则更加灵活,可以根据实际需要动态地分配和释放内存。

C语言提供了一些内存管理函数,如malloc、calloc和realloc,用于动态分配内存空间。

这些函数可以根据需要分配指定大小的内存,并返回一个指向该内存的指针。

使用完毕后,可以通过调用free函数来释放这些内存空间,以便其他部分可以重新利用。

动态内存分配的好处是节省内存资源,但是需要开发人员自己负责内存的管理,否则容易出现内存泄漏等问题。

二、内存泄漏和内存溢出内存泄漏是指在程序运行时分配了内存空间,但在不再使用时未能及时释放,导致这部分内存无法再次被利用。

内存泄漏会导致程序占用过多的内存资源,从而降低系统的性能和稳定性。

内存溢出则是指程序在申请内存空间时,超出了系统或进程所能提供的最大内存限制。

当程序试图分配超过系统或进程限制的内存时,会导致内存溢出。

内存溢出可能导致程序崩溃或产生未定义的行为。

为了避免内存泄漏和内存溢出的问题,开发人员需要注意以下几点:1. 动态内存分配后,必须在使用完毕后及时调用free函数释放内存。

2. 在循环中进行动态内存分配时,需要确保每次循环都释放之前分配的内存,以避免内存泄漏。

c语言进阶

c语言进阶

c语言进阶1.内存管理a. 未初始化的全局变量(.bss)b. 初始化的全局变量(.data)c. 常量数据(.rodata):常量不一定放在.rodata里,有的立即数直接和指令编码在一起,存放在代码段(.text)d. 代码段(.text)f. 栈(stack):用于存放临时变量和函数参数。

栈向下增长(低地址)。

g. 堆(heap):内存分配了不释放,被称为内存泄漏(Memory Leak)2.内存分配方式a.从静态存储区分布:内存在编译时就已经分配好,这块内存在程序的整个运行期间都存在,如全局变量,static 变量等。

b.在栈上创建:函数内部局部变量,函数执行结束时被释放。

c.在堆上创建:动态内存分配。

malloc 和new的时候。

要free 和delete3.野指针a. 指针变量没有被初始化b. 指针p被free或者delete之后,没有置位NULL4.指针和数组对比a. 数组要么在静态存储区被创建,要么在栈上被创建。

数组名对应着一块内存(而不是指向),其地址和容量在生命期内保持不变,数组内容可以保持不变b. 指针可以指向任意类型的内存块。

c. sizeof(a):得到数组真实的大小; sizeof(p):指针变量的字节数5.预处理a. 宏定义b. 文件包含;<>表示在包含文件目录中区查找 ""表示首先在当前源文件目录中去查找,若未找到则去包含目录中去找c. 条件编译6.函数库的提供形式:静态链接库和动态链接库a. 静态链接库:b. 动态链接库:效率更高。

不是将库函数的代码直接复制进可执行程序中,只是做个链接标记。

当应用程序在内存中执行,运行时环境发现它调用了一个动态库中的库函数时,会加载这个动态库到内存中,以后不管有多少个应用程序在同时使用该库函数,该库函数在内存中只有一份。

7.链接属性a. 程序从源代码到最终可执行程序:预编译、编译(将源代码翻译成xx.o)、汇编和链接b. 内存映像:代码段(test)和rodata段;数据段(data)和bss 段;堆;文件映射区(进程打开了文件后,将这个文件的内容从硬盘读取到进程的文件映射区,以后就直接在内存中操作这个文件);栈;内核映射区(将操作系统的内核程序映射到这个区域)8.加载运行代码a. 单独个人写的C语言程序没法直接在内存中运行,需要一定的外部协助,这段协助的代码叫做加载运行代码,这段代码的主要作用是给全局变量赋值,清bss段(现象:C语言中未初始化的全局变量默认为0)b. 在裸机下写的代码:定义了一个全局变量初始化为0.但是实际不为0.应在裸机的start.s中加入清bss段代码9.存储类相关的关键字auto:修饰局部变量。

操作系统c语言设计程序模拟内存的动态分区内存管理方法。内存分区使用分区(说明)

操作系统c语言设计程序模拟内存的动态分区内存管理方法。内存分区使用分区(说明)

操作系统c语言设计程序模拟内存的动态分区内存管理方法。

内存分区使用分区(说明)摘要:1.引言2.内存动态分区原理a.内存分区类型b.内存分区算法3.C语言实现内存动态分区管理a.内存分配函数b.内存释放函数c.内存管理函数4.内存动态分区管理的应用a.进程管理b.文件系统5.内存分区管理的优化a.算法改进b.硬件支持6.结论正文:【引言】内存管理是操作系统中的核心功能之一,它负责对系统内存进行有效分配、管理和回收。

在众多内存管理方法中,动态分区管理因其灵活性和高效性而得到了广泛应用。

本文将介绍操作系统中动态分区管理的原理,以及如何使用C语言实现这一管理方法。

【内存动态分区原理】内存动态分区管理主要包括两个方面:内存分区类型和内存分区算法。

a.内存分区类型内存分区通常分为两类:固定大小分区和不固定大小分区。

固定大小分区是指内存中被分配成固定大小的分区,适用于内存需求稳定的场景。

不固定大小分区则根据实际需求进行分配,更加灵活。

b.内存分区算法内存分区算法主要包括首次适应算法(FF)、最佳适应算法(BF)、最坏适应算法(WF)等。

首次适应算法简单、快速分配,但可能导致内存碎片;最佳适应算法尽量使用最小空间满足需求;最坏适应算法则优先使用大内存块,分割后空闲块仍较大。

【C语言实现内存动态分区管理】在C语言中,我们可以通过编写内存分配函数、内存释放函数和内存管理函数来实现内存动态分区管理。

a.内存分配函数内存分配函数负责根据用户请求分配内存。

可以根据内存分区类型和内存分区算法实现。

例如,首次适应算法可以遍历空闲内存块表,找到第一个满足需求的空闲块并进行分配。

b.内存释放函数内存释放函数负责回收不再使用的内存块,将其归还给空闲内存池。

释放内存时,需要确保该内存块之后的内存块不会被误用。

c.内存管理函数内存管理函数负责监控内存使用情况,如内存总量、空闲内存块数量等,以便在必要时进行内存扩容或压缩。

【内存动态分区管理的应用】内存动态分区管理在操作系统中有着广泛应用,如进程管理和文件系统等。

C语言内存管理与安全性

C语言内存管理与安全性

C语言内存管理与安全性在计算机科学领域,C语言是一门被广泛使用的编程语言,因为其高效性和灵活性而受到开发者的青睐。

然而,C语言也存在一些特殊问题,尤其是与内存管理和安全性相关的问题。

本文将探讨C语言的内存管理原则、内存泄露、缓冲区溢出等安全性问题,并提供相应的解决方案。

一、内存管理原则在C语言中,内存管理是程序员应该特别关注的重要的任务之一。

以下是一些C语言内存管理的基本原则:1. 动态内存分配:C语言中,程序员可以使用malloc()和free()函数来动态分配和释放内存。

动态内存分配可以根据程序的需要进行灵活的内存管理。

2. 避免内存泄露:内存泄露是指程序在分配内存后没有释放该内存,造成内存浪费的现象。

为了避免内存泄露,程序员需要在适当的时候调用free()函数来释放已分配的内存。

3. 内存一致性:内存一致性是指程序访问的内存地址是有效且可靠的。

程序员需要遵循规定的读写内存的顺序以确保内存一致性。

4. 常量内存:C语言中,程序员可以使用const关键字来声明常量,以防止对常量内存的非法修改。

二、内存泄露内存泄露是C语言中常见的问题之一,它会导致程序占用过多的内存资源,影响程序的性能。

以下是一些常见的原因和解决方案:1. 未释放内存:程序员需要确保在不再使用动态分配的内存时,及时使用free()函数释放该内存。

同时,程序中应避免在释放内存后仍然使用这些内存空间。

2. 循环引用:当存在循环引用时,即两个或多个对象之间相互引用,而没有其他引用指向它们时,会导致内存泄露。

此时,可以使用适当的引用计数算法来解决循环引用导致的内存泄露问题。

三、缓冲区溢出缓冲区溢出是C语言中的一种常见安全性问题。

当程序写入超过缓冲区容量的数据时,会导致数据覆盖其他内存地址,从而引发安全漏洞。

以下是一些常见的原因和解决方案:1. 字符串处理:在C语言中,字符串处理时需要格外小心,使用strncpy()函数来确保不会发生缓冲区溢出。

c++ 内存管理机制

c++ 内存管理机制

c++ 内存管理机制C++ 是一种编程语言,它支持面向对象编程和泛型编程。

这种编程语言在内存管理方面提供了强大的支持,使得程序员不必关心内存管理细节。

这篇文章将介绍 C++ 内存管理机制的基本概念、原理和实现方法。

一、内存管理机制的基本概念内存管理机制是指在程序运行时对内存进行分配、释放、复制等操作的过程。

在 C++ 中,内存管理分为两种:动态内存管理和静态内存管理。

动态内存管理是指程序在运行时根据需要分配或释放内存。

这种内存由程序员控制。

动态内存的分配和释放可以通过 malloc、new、calloc、realloc 等函数来完成。

静态内存管理是指程序在编译时就已经将内存分配好了。

C++ 中的全局变量和静态变量都是静态内存,它们的内存分配是由编译器完成的。

在程序运行时,程序无法修改或释放静态内存。

二、内存管理的原理内存管理的原理是基于计算机的硬件和操作系统的支持。

计算机的内存是通过地址来寻址的,每个内存单元都有一个唯一的地址。

操作系统为程序提供了访问内存的接口。

程序通过这些接口来请求分配内存,释放内存和管理内存。

内存分配的关键在于内存的管理,即如何跟踪哪些内存被分配,哪些内存被释放,哪些内存是可用的。

C++ 使用堆和栈来管理内存。

堆是动态内存分配和回收的区域。

当程序需要分配一块内存时,它可以使用 new 或malloc 函数来请求分配一块地址连续的内存空间。

堆可以分为多个内存块,每个内存块都可以独立地分配和释放。

程序员需要手动管理堆内存,即在使用完内存后,需要调用delete 或 free 函数将内存释放。

栈则用于管理静态内存。

当程序声明一个变量时,它会被分配到栈上。

栈是一种后进先出 (LIFO) 的数据结构。

当程序需要释放一块栈内存时,它只需要将栈指针向上移动即可。

三、内存管理的实现方法C++ 使用指针来管理内存。

指针是一种变量,它保存了内存块的地址。

指针可以指向堆中的动态内存块,也可以指向栈中的静态内存块。

c语言的内存结构

c语言的内存结构

c语言的内存结构C语言是一种高级编程语言,但实际上在计算机中运行时,C语言程序会被编译成可执行文件,然后在计算机内存中运行。

因此,了解C 语言的内存结构对于理解C程序的运行及性能优化至关重要。

C语言的内存结构主要可以分为以下几个部分:栈(Stack)、堆(Heap)、全局内存(Global Memory)和代码区(Code Segment)。

首先是栈(Stack),栈是一种自动分配和释放内存的数据结构。

它用于存储局部变量、函数参数和函数调用信息等。

栈的特点是后进先出(LIFO),也就是最后进入的数据最先被释放。

栈的大小在程序运行时是固定的,一般由编译器设置。

栈的操作速度较快,但内存空间有限。

其次是堆(Heap),堆是一种动态分配和释放内存的数据结构。

它用于存储动态分配的变量、数据结构和对象等。

堆的大小一般由操作系统管理,并且可以在运行时进行动态扩展。

堆的操作相对较慢,因为需要手动分配和释放内存,并且容易产生内存碎片。

全局内存(Global Memory)是用于存储全局变量和静态变量的区域。

全局变量在程序的生命周期内都存在,并且可以在多个函数之间共享。

静态变量作用于其所在的函数内,但是生命周期与全局变量相同。

全局内存由编译器进行分配和管理。

代码区(Code Segment)存储了程序的指令集合,它是只读的。

在程序运行时,代码区的指令会被一条一条地执行。

代码区的大小由编译器决定,并且在程序执行过程中不能修改。

此外,C语言还具有特殊的内存区域,如常量区和字符串常量区。

常量区用于存储常量数据,如字符串常量和全局常量等。

常量区的数据是只读的,且在程序的整个生命周期内存在。

字符串常量区是常量区的一个子区域,用于存储字符串常量。

在C语言中,内存分配和释放是程序员的责任。

通过使用malloc和free等函数,程序员可以在堆中动态地分配和释放内存,从而灵活地管理程序的内存使用。

不过,应当注意避免内存泄漏和野指针等问题,以免出现内存错误和性能问题。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

c++中涉及到的内存的管理问题可以归结为两方面:正确地得到它和有效地使用它。

好的程序员会理解这两个问题为什么要以这样的顺序列出。

因为执行得再快、体积再小的程序如果它不按你所想象地那样去执行,那也一点用处都没有。

“正确地得到”的意思是正确地调用内存分配和释放程序;而“有效地使用”是指写特定版本的内存分配和释放程序。

这里,“正确地得到”显得更重要一些。

然而说到正确性,c++其实从c继承了一个很严重的头疼病,那就是内存泄露隐患。

虚拟内存是个很好的发明,但虚拟内存也是有限的,并不是每个人都可以最先抢到它。

在c中,只要用malloc分配的内存没有用free返回,就会产生内存泄露。

在c++中,肇事者的名字换成了new和delete,但情况基本上是一样的。

当然,因为有了析构函数的出现,情况稍有改善,因为析构函数为所有将被摧毁的对象提供了一个方便的调用delete的场所。

但这同时又带来了更多的烦恼,因为new 和delete是隐式地调用构造函数和析构函数的。

而且,因为可以在类内和类外自定义new和delete操作符,这又带来了复杂性,增加了出错的机会。

下面的条款(还有条款m8)将告诉你如何避免产生那些普遍发生的问题。

5:对应的new和delete要采用相同的形式下面的语句有什么错?string *stringarray = new string[100];...delete stringarray;一切好象都井然有序——一个new对应着一个delete——然而却隐藏着很大的错误:程序的运行情况将是不可预测的。

至少,stringarray指向的100个string 对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。

用new的时候会发生两件事。

首先,内存被分配(通过operator new 函数,详见条款7-10和条款m8),然后,为被分配的内存调用一个或多个构造函数。

用delete的时候,也有两件事发生:首先,为将被释放的内存调用一个或多个析构函数,然后,释放内存(通过operator delete 函数,详见条款8和m8)。

对于 delete来说会有这样一个重要的问题:内存中有多少个对象要被删除?答案决定了将有多少个析构函数会被调用。

这个问题简单来说就是:要被删除的指针指向的是单个对象呢,还是对象数组?这只有你来告诉delete。

如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组:string *stringptr1 = new string;string *stringptr2 = new string[100];...delete stringptr1;// 删除一个对象delete [] stringptr2;// 删除对象数组如果你在stringptr1前加了"[]"会怎样呢?答案是:那将是不可预测的;如果你没在stringptr2前没加上"[]"又会怎样呢?答案也是:不可预测。

而且对于象int这样的固定类型来说,结果也是不可预测的,即使这样的类型没有析构函数。

所以,解决这类问题的规则很简单:如果你调用new时用了[],调用delete 时也要用[]。

如果调用new时没有用[],那调用delete时也不要用[]。

在写一个包含指针数据成员,并且提供多个构造函数的类时,牢记这一规则尤其重要。

因为这样的话,你就必须在所有初始化指针成员的构造函数里采用相同的new的形式。

否则,析构函数里将采用什么形式的delete呢?关于这一话题的进一步阐述,参见条款11。

这个规则对喜欢用typedef的人来说也很重要,因为写typedef的程序员必须告诉别人,用new创建了一个typedef定义的类型的对象后,该用什么形式的delete来删除。

举例如下:typedef string addresslines[4]; //一个人的地址,共4行,每行一个string//因为addresslines是个数组,使用new: string *pal = new addresslines; // 注意"new addresslines"返回string*, 和// "new string[4]"返回的一样delete时必须以数组形式与之对应:delete pal;// 错误!delete [] pal;// 正确为了避免混乱,最好杜绝对数组类型用typedefs。

这其实很容易,因为标准c++库(见条款49)包含有stirng和vector模板,使用他们将会使对数组的需求减少到几乎零。

举例来说,addresslines可以定义为一个字符串(string)的向量(vector),即addresslines可定义为vector<string>类型。

6:析构函数里对指针成员调用delete大多数情况下,执行动态内存分配的的类都在构造函数里用new分配内存,然后在析构函数里用delete释放内存。

最初写这个类的时候当然不难做,你会记得最后对在所有构造函数里分配了内存的所有成员使用delete。

然而,这个类经过维护、升级后,情况就会变得困难了,因为对类的代码进行修改的程序员不一定就是最早写这个类的人。

而增加一个指针成员意味着几乎都要进行下面的工作:·在每个构造函数里对指针进行初始化。

对于一些构造函数,如果没有内存要分配给指针的话,指针要被初始化为0(即空指针)。

·删除现有的内存,通过赋值操作符分配给指针新的内存。

·在析构函数里删除指针。

如果在构造函数里忘了初始化某个指针,或者在赋值操作的过程中忘了处理它,问题会出现得很快,很明显,所以在实践中这两个问题不会那么折磨你。

但是,如果在析构函数里没有删除指针,它不会表现出很明显的外部症状。

相反,它可能只是表现为一点微小的内存泄露,并且不断增长,最后吞噬了你的地址空间,导致程序夭折。

因为这种情况经常不那么引人注意,所以每增加一个指针成员到类里时一定要记清楚。

另外,删除空指针是安全的(因为它什么也没做)。

所以,在写构造函数,赋值操作符,或其他成员函数时,类的每个指针成员要么指向有效的内存,要么就指向空,那在你的析构函数里你就可以只用简单地delete掉他们,而不用担心他们是不是被new过。

当然对本条款的使用也不要绝对。

例如,你当然不会用delete去删除一个没有用new来初始化的指针,而且,就象用智能指针对象时不用劳你去删除一样,你也永远不会去删除一个传递给你的指针。

换句话说,除非类成员最初用了new,否则是不用在析构函数里用delete的。

说到智能指针,这里介绍一种避免必须删除指针成员的方法,即把这些成员用智能指针对象来代替,比如c++标准库里的auto_ptr。

想知道它是如何工作的,看看条款m9和m10。

7:预先准备好内存不够的情况operator new在无法完成内存分配请求时会抛出异常(以前的做法一般是返回0,一些旧一点的编译器还这么做。

你愿意的话也可以把你的编译器设置成这样。

关于这个话题我将推迟到本条款的结尾处讨论)。

大家都知道,处理内存不够所产生的异常真可以算得上是个道德上的行为,但实际做起来又会象刀架在脖子上那样痛苦。

所以,你有时会不去管它,也许一直没去管它。

但你心里一定还是深深地隐藏着一种罪恶感:万一new真的产生了异常怎么办?你会很自然地想到处理这种情况的一种方法,即回到以前的老路上去,使用预处理。

例如,c的一种常用的做法是,定义一个类型无关的宏来分配内存并检查分配是否成功。

对于c++来说,这个宏看起来可能象这样:#define new(ptr, type) \try { (ptr) = new type; } \catch (std::bad_alloc&) { assert(0); }(“慢!std::bad_alloc是做什么的?”你会问。

bad_alloc是operator new 不能满足内存分配请求时抛出的异常类型,std是bad_alloc所在的名字空间(见条款28)的名称。

“好!”你会继续问,“assert又有什么用?”如果你看看标准c头文件<assert.h>(或与它相等价的用到了名字空间的版本<cassert>,见条款49),就会发现assert是个宏。

这个宏检查传给它的表达式是否非零,如果不是非零值,就会发出一条出错信息并调用abort。

assert只是在没定义标准宏ndebug的时候,即在调试状态下才这么做。

在产品发布状态下,即定义了ndebug 的时候,assert什么也不做,相当于一条空语句。

所以你只能在调试时才能检查断言(assertion))。

new宏不但有着上面所说的通病,即用assert去检查可能发生在已发布程序里的状态(然而任何时候都可能发生内存不够的情况),同时,它还在c++里有另外一个缺陷:它没有考虑到new有各种各样的使用方式。

例如,想创建类型t对象,一般有三种常见的语法形式,你必须对每种形式可能产生的异常都要进行处理:new t;new t(constructor arguments);new t[size];这里对问题大大进行了简化,因为有人还会自定义(重载)operator new,所以程序里会包含任意个使用new的语法形式。

那么,怎么办?如果想用一个很简单的出错处理方法,可以这么做:当内存分配请求不能满足时,调用你预先指定的一个出错处理函数。

这个方法基于一个常规,即当operator new不能满足请求时,会在抛出异常之前调用客户指定的一个出错处理函数——一般称为new-handler函数。

(operator new实际工作起来要复杂一些,详见条款8)指定出错处理函数时要用到set_new_handler函数,它在头文件<new>里大致是象下面这样定义的:typedef void (*new_handler)();new_handler set_new_handler(new_handler p) throw();可以看到,new_handler是一个自定义的函数指针类型,它指向一个没有输入参数也没有返回值的函数。

set_new_handler则是一个输入并返回new_handler类型的函数。

set_new_handler的输入参数是operator new分配内存失败时要调用的出错处理函数的指针,返回值是set_new_handler没调用之前就已经在起作用的旧的出错处理函数的指针。

可以象下面这样使用set_new_handler:// function to call if operator new can't allocate enough memoryvoid nomorememory(){cerr << "unable to satisfy request for memory\n";abort();}int main(){set_new_handler(nomorememory);int *pbigdataarray = new int[100000000];...}假如operator new不能为100,000,000个整数分配空间,nomorememory将会被调用,程序发出一条出错信息后终止。

相关文档
最新文档