在C++中对象可以静态分配——即编译器在处理程序源代码时分配,也可以动态分配——即程序执行时调用运行时刻库函数来分配。这两种内存分配方法的主要区别是效率与灵活性之间的平衡准则不同。出于静态内存分配是在程序执行之前进行的,因而效率比较高。但是,他缺少灵活性,他要求在程序执行之前就直到所需内存的类型和数量。例如,利用静态分配的字符串数组,我们无法很容易的处理和存储任意的文本文件。一般来说,存储未知数目的元素需要动态内存分配的灵活性。
以下内存分配为静态的,例如:int ival = 1024; 指示编译器分配足够的存储区以存放一个整型值,该存储区与名字 ival 相关联。然后用数值1024初始化该存储区。这些工作都是在程序执行之前完成的。
有两个值与对象 ival 相关联:一个是它包含的值——本例中是1024,另一个是存放这个值的存储区的地址。在C++中,这两个值都可以被访问。当我们写代码: int ival2 = ival + 1;时,我们访问 ival 所包含的值,并把它加 1 ,然后再用该新值初始化 ival2 。在本例中,ival2的值是1025,怎样访问他的地址呢?
C++支持用指针类型来存放对象的内存地址值。 例如,为了声明一个能存放 ival 内存地址的指针类型。 我们可以写成: int *pint; C++预定义了一个专门取地址的操作符(&)。当我们把他应用在一对象时,返回的是对像的地址值。因此,为了将 ival的内存地址值赋给 pint ,我们可以写成:int *pint; pint = &ival; 为了访问 pint 所指向的实际对象,我们必须先用解引用操作符(*)来接触 pint 的引用。例如,我们通过 pint 间接给 ival 加1:*pint = *pint +1 ; 它等价于对 ival 操作的语句:ival = ival + 1;
在C++中,指针的主要用处是管理和操纵动态分配的内存。静态与动态内存分配的两个主要区别是:
- 静态对象是有名字的变量,我们直接对其进行操作。而动态对象是没有名字的变量,我们通过指针间接的对它进行操作。
- 静态对象的分配与释放由编译器自动处理,程序员需要理解这一点,但不需要做任何事情。相反,动态对象的分配与释放,必须由程序员显式的管理,相对来说比较容易出错,他通过 new 和 delete 两个表达式来完成。
对象的动态分配可通过 new 表达式的两个版本之一来完成。第一个版本用于分配特定类型的单个对象,例如: int *pint = new int(10); 分配了一个没有名字的int 类型的对象,对象初始值为 1024 。然后表达式返回对象在内存中的地址。接着这个地址被用来初始化指针对象 pint。对于动态分配的内存,唯一的访问是通过指针间接访问。
new 表达式的第二个版本,用于分配特定类型和维数的数组。例如: int *pia = new int [4]; 分配了含有四个元素的整型数组。我们不可以给动态分配的数组的每个元素显式地指定一个初始值。
分配动态数组时一个常令人迷惑的问题是,返回值只是一个指针,与分配动态单一动态对象的返回类型相同,例如,pint 与 pia的不同之处在于,pia 拥有四元素数组第一个元素的地址,而 pint 只是简单的包含了一个单一对象的地址。当用完了动态分配的对象或对象数组后,我们必须显式地释放这些内存。我们可以通过 delete 表达式的两个版本之一来完成这件事情,而释放之后的内存则可以被程序重新使用。单一对象的 delete 表达式形式:delete pint; 数组形式的delete 表达式:delete [] pia;
如果忘了释放动态分配的内存,又会怎么样呢?答案就是,程序会出现内存泄漏(memory leak)的问题。内存泄漏是指一块动态分配的内存,我们不再拥有指向这块内存的指针,因此我们没有办法将它返还给程序供以后使用。
本文深入探讨C++中静态与动态内存分配的区别,包括它们的工作原理、指针的应用、new和delete表达式的使用,以及不当内存管理可能导致的内存泄漏问题。

3494

被折叠的 条评论
为什么被折叠?



