C++ 动态内存
要成为一名优秀的 C++ 程序员,充分理解 C++ 中动态内存的工作原理至关重要。C++ 程序中的内存分为两部分:
栈 - 函数内声明的所有变量都会占用栈中的内存。
堆 - 这是程序中未使用的内存,可用于在程序运行时动态分配内存。
很多时候,您无法提前知道在定义的变量中存储特定信息需要多少内存,所需内存的大小可以在运行时确定。
您可以使用 C++ 中的特殊运算符在运行时在堆中为给定类型的变量分配内存,该运算符返回分配空间的地址。此运算符称为 new 运算符。
如果您不再需要动态分配的内存,可以使用 delete 运算符,它会取消分配先前由 new 运算符分配的内存。
new 和 delete 运算符
以下是使用 new 运算符为任何数据类型动态分配内存的通用语法。
new data-type;
这里的 data-type 可以是任何内置数据类型(包括数组)或任何用户定义的数据类型(包括类或结构体)。我们先从内置数据类型开始。例如,我们可以将指针定义为 double 类型,然后在执行时请求分配内存。我们可以使用 new 运算符来实现这一点,如下所示:-
double* pvalue = NULL; // 指针初始化为 null pvalue = new double; // 为变量申请内存
如果空闲存储空间已用完,则可能未成功分配内存。因此,最好检查 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 运算符在空闲存储区中释放它所占用的内存,如下所示:-
delete pvalue; // 释放 pvalue 指向的内存
让我们将上述概念结合起来,并通过以下示例来展示 new 和 delete 的工作原理:-
#include <iostream> using namespace std; int main () { double* pvalue = NULL; // 指针初始化为 null pvalue = new double; // 为变量申请内存 *pvalue = 29494.99; // 将值存储在分配的地址 cout << "Value of pvalue : " << *pvalue << endl; delete pvalue; // 释放内存。 return 0; }
如果我们编译并运行上述代码,将产生以下结果 -
Value of pvalue : 29495
数组的动态内存分配
假设您要为一个字符数组(即包含 20 个字符的字符串)分配内存。使用与上面相同的语法,我们可以动态分配内存,如下所示。
char* pvalue = NULL; // 指针初始化为 null pvalue = new char[20]; // 为变量申请内存
要删除刚刚创建的数组,语句如下:-
delete [] pvalue; // 删除 pvalue 指向的数组
遵循与 new 运算符类似的通用语法,您可以按如下方式为多维数组分配内存 -
double** pvalue = NULL; // 指针初始化为 null pvalue = new double [3][4]; // 为 3x4 数组分配内存
但是,释放多维数组内存的语法仍然与上述相同 -
delete [] pvalue; // 删除 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; // 删除数组 return 0; }
如果要分配一个包含四个 Box 对象的数组,则 Simple 构造函数将被调用四次;同样,在删除这些对象时,析构函数也将被调用相同次数。
如果我们编译并运行上述代码,将产生以下结果 -
Constructor called! Constructor called! Constructor called! Constructor called! Destructor called! Destructor called! Destructor called! Destructor called!