Home C&C++函数库 c++ 语法 程序源码 Linux C库

动态内存

在前几章所见的程序中,所有需要的内存都是在程序执行之前通过定义需要的变量来确定的。 但是也有一些情况,程序的内存需求只能在运行时确定。例如,需要的内存取决于用户输入。 在这些情况下,程序需要动态分配内存,c++语言为此集成了new和delete操作符。

☞ 操作符 new 和 new[]



动态内存是使用new操作符分配的。New后面跟着一个数据类型说明符, 如果需要一个包含多个元素的序列,则在方括号[]中显示这些元素的数量。 它返回一个指向已分配的新内存块开始的指针。它的语法是:

pointer = new type
pointer = new type [number_of_elements]

第一个表达式用于分配内存类型为type的元素。 第二个用于分配类型为type的元素块(数组),其中number_of_elements是表示这些元素数量的整数值。例如:

int * foo;
foo = new int [5];

在这种情况下,系统为5个int类型的元素动态分配空间,并返回一个指向序列的第一个元素的指针, 该指针被赋值给foo(一个指针)。因此,foo现在指向一个有效的内存块,其中包含5个int类型的元素。

在这里,foo是一个指针,因此,foo所指向的第一个元素可以通过表达式foo[0]或表达式*foo访问(两者是等价的)。 第二个元素可以用foo[1]或*(foo+1)访问,以此类推。

声明一个普通数组和使用new为一个内存块分配动态内存之间有很大的区别。 最重要的区别是,程序运行之前,一个常规数组中需要一个常数表达式确定它的大小, 而动态内存分配允许在运行时分配内存,使用任何变量值的大小。

程序所请求的动态内存是由系统从内存堆中分配的。然而,计算机内存是有限的资源, 它可以耗尽。因此,不能保证所有使用操作符 new分配内存的请求系统都能响应.

c++提供了两种标准机制来检查分配是否成功:

一是通过处理异常。使用此方法,当分配失败时将抛出bad_alloc类型的异常。 异常是一种强大的c++特性,将在本教程的后面部分进行解释。 但是现在,您应该知道,如果抛出这个异常,假如它不能由特定的处理程序处理,则程序执行将被终止。

这种方法是new默认使用的方法,并且在如下声明中使用:

foo = new int [5];  //如果分配失败,将引发异常

另一种方法称为nothrow,当使用该方法时,当内存分配失败时,new返回的指针是空指针, 程序继续正常执行,而不是抛出bad_alloc异常或终止程序。

这个方法可以通过使用一个名为nothrow的特殊对象来指定, 该对象在头文件 <new>中声明,作为new的参数:

foo = new (nothrow) int [5]; 

在这种情况下,如果这块内存分配失败,可以通过检查foo是否是一个空指针来检测失败:

int * foo;
foo = new (nothrow) int [5];
if (foo == nullptr) {
  // 错误分配内存。处理错误。
}

这个nothrow方法产生的代码效率可能低于异常,因为它显式地要求检查每次分配后返回的指针值。 因此,至少对于关键分配,通常首选异常机制。尽管如此,由于nothrow机制的简单性, 接下来的大多数示例将使用nothrow机制。

☞ 操作符 delete 和 delete[]



在大多数情况下,只需要在程序的特定时间段内动态分配内存;一旦不再需要它, 就可以释放它,以便该内存再次对其他动态内存请求可用。这就是delete操作符的目的,它的语法是:

delete pointer;
delete[] pointer;

第一个语句释放使用new分配的单个元素的内存,第二个语句释放使用new和在方括号([]) 中包含size的元素数组分配的内存。

作为参数传递给delete的值要么是一个指针,指向以前分配给new的内存块, 要么是一个null pointer(空指针的情况下,delete不起作用)。

// rememb-o-matic
#include <iostream>
#include <new>
using namespace std;

int main ()
{
  int i,n;
  int * p;
  cout << "How many numbers would you like to type? ";
  cin >> i;
  p= new (nothrow) int[i];
  if (p == nullptr)
    cout << "Error: memory could not be allocated";
  else
  {
    for (n=0; n < i; n++)
    {
      cout << "Enter number: ";
      cin >> p[n];
    }
    cout << "You have entered: ";
    for (n=0; n < i; n++)
      cout << p[n] << ", ";
    delete[] p;
  }
  return 0;
}
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,

注意,new语句中括号内的值是用户(i)输入的变量值,而不是常量表达式:

p= new (nothrow) int[i];

总是存在这样一种可能性,即用户为i输入的值太大,以至于系统无法为其分配足够的内存。 例如,当我试图给“多少个数字”的问题提供一个10亿的值时, 我的系统不能为程序分配那么多的内存,我得到了我们为这种情况准备的文本消息(错误:内存无法分配)。

对于程序来说,通过检查指针值(如果nothrow)或捕获相应的异常, 总是能够处理分配内存的失败被认为是一种良好的习惯。

☞ C 中的动态内存



c++集成了new和delete操作符来分配动态内存。但这些在C语言中是不可用的;相反, 它使用了一个库解决方案,在头文件<cstdlib>(在C中称为<stdlib.h>)中定义了malloc, calloc, realloc和free函数。这些函数在c++中也可用,也可以用于分配和释放动态内存。

但是,请注意,这些函数分配的内存块不一定与new函数返回的内存块兼容, 所以它们不应该混合使用;每一个都应该用它自己的一组函数或操作符来处理。



联系我们 免责声明 关于CandCplus 网站地图