C++ 动态内存
充分理解动态内存在 C++ 中的实际工作原理对于成为一名优秀的 C++ 程序员至关重要。C++ 程序中的内存分为两部分 -
堆栈- 函数内声明的所有变量都将从堆栈中占用内存。
堆- 这是程序未使用的内存,可用于在程序运行时动态分配内存。
很多时候,您事先并不知道在定义的变量中存储特定信息需要多少内存,并且所需内存的大小可以在运行时确定。
您可以在运行时使用 C++ 中的特殊运算符在堆内为给定类型的变量分配内存,该运算符返回所分配空间的地址。该运算符称为new运算符。
如果不再需要动态分配的内存,可以使用delete运算符,它会取消分配先前由new运算符分配的内存。
新建和删除运算符
有以下通用语法使用new运算符为任何数据类型动态分配内存。
new data-type;
这里,数据类型可以是任何内置数据类型,包括数组或任何用户定义的数据类型,包括类或结构。让我们从内置数据类型开始。例如,我们可以定义一个指向 double 类型的指针,然后请求在执行时分配内存。我们可以使用new运算符和以下语句来做到这一点 -
double* pvalue = NULL; // Pointer initialized with null pvalue = new double; // Request memory for the variable
如果可用存储已用完,则内存可能未成功分配。因此,最好检查 new 运算符是否返回 NULL 指针并采取适当的操作,如下所示 -
double* pvalue = NULL; if( !(pvalue = new double )) { cout << "Error: out of memory." <<endl; exit(1); }
C 中的malloc ()函数在 C++ 中仍然存在,但建议避免使用 malloc() 函数。new 相对于 malloc() 的主要优点是 new 不只是分配内存,它还构造对象,这是 C++ 的主要目的。
在任何时候,当您觉得不再需要动态分配的变量时,您可以使用“删除”运算符释放它在自由存储中占用的内存,如下所示 -
delete pvalue; // Release memory pointed to by pvalue
让我们将上述概念并形成以下示例来展示“新建”和“删除”如何工作 -
#include <iostream> using namespace std; int main () { double* pvalue = NULL; // Pointer initialized with null pvalue = new double; // Request memory for the variable *pvalue = 29494.99; // Store value at allocated address cout << "Value of pvalue : " << *pvalue << endl; delete pvalue; // free up the memory. return 0; }
如果我们编译并运行上面的代码,将产生以下结果 -
Value of pvalue : 29495
数组的动态内存分配
假设您想要为字符数组(即 20 个字符的字符串)分配内存。使用上面使用的相同语法,我们可以动态分配内存,如下所示。
char* pvalue = NULL; // Pointer initialized with null pvalue = new char[20]; // Request memory for the variable
要删除我们刚刚创建的数组,语句将如下所示 -
delete [] pvalue; // Delete array pointed to by pvalue
遵循 new 运算符的类似通用语法,您可以分配多维数组,如下所示 -
double** pvalue = NULL; // Pointer initialized with null pvalue = new double [3][4]; // Allocate memory for a 3x4 array
但是,释放多维数组内存的语法仍然与上面相同 -
delete [] pvalue; // Delete array pointed to by pvalue
对象的动态内存分配
对象与简单数据类型没有什么不同。例如,考虑以下代码,我们将使用对象数组来阐明概念 -
#include <iostream> using namespace std; class Box { public: Box() { cout << "Constructor called!" <<endl; } ~Box() { cout << "Destructor called!" <<endl; } }; int main() { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // Delete array return 0; }
如果要分配四个 Box 对象的数组,则 Simple 构造函数将被调用四次,同样,在删除这些对象时,析构函数也将被调用相同的次数。
如果我们编译并运行上面的代码,将产生以下结果 -
Constructor called! Constructor called! Constructor called! Constructor called! Destructor called! Destructor called! Destructor called! Destructor called!