C++ 动态内存
理解C++中动态内存的工作原理对于成为一名优秀的C++程序员至关重要。你的C++程序的内存被分为两部分−
- 堆栈 − 函数内部声明的所有变量将占用堆栈中的内存。
-
堆 − 这是程序中未使用的内存,当程序运行时可以用于动态分配内存。
很多时候,你事先不知道需要多少内存来存储特定信息在定义的变量中,所需内存的大小可以在运行时确定。
你可以在堆中为给定类型的变量在运行时分配内存,使用C++中的特殊运算符,该运算符返回分配空间的地址。这个运算符被称为 new 运算符。
如果你不再需要动态分配的内存,你可以使用 delete 运算符,它会释放之前由new运算符分配的内存。
new和delete运算符
以下是通用语法,用于使用 new 运算符为任何数据类型动态分配内存。
new data-type;
在这里, data-type 可以是任何内置的数据类型,包括数组或任何用户定义的数据类型,包括类或结构体。让我们从内置的数据类型开始。例如,我们可以定义一个指向double类型的指针,然后在执行时请求分配内存。我们可以使用 new 操作符和以下语句来实现这一点:
double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
如果使用的自由存储空间已经耗尽,那么可能无法成功分配内存。因此,良好的做法是检查new运算符是否返回空指针,并采取相应的措施,如下所示−
double* pvalue = NULL;
if( !(pvalue = new double )) {
cout << "Error: out of memory." <<endl;
exit(1);
}
C中的 malloc() 函数在C++中仍然存在,但建议避免使用malloc()函数。new的主要优势是,它不仅分配内存,还构造对象,这是C++的主要目的。
在任何时候,当您感觉不再需要动态分配的变量时,您可以使用’ delete ‘运算符释放占据free store中的内存,如下所示−
delete pvalue; // Release memory pointed to by pvalue
让我们将上述概念放在一起,形成以下示例,以展示’new’和’delete’是如何工作的 –
#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!