Tizeng's blog Ordinary Gamer

C++的动态内存

2019-02-26
Tizeng

  • 栈:在函数内部声明的所有变量都将占用栈内存

  • 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存

在C++中,可以使用new运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。如果您不再需要动态分配的内存空间,可以使用delete运算符,删除之前由new运算符分配的内存。

new的功能是在堆区新建一个对象,并返回该对象的指针。所谓的新建对象的意思就是,将调用该类的构造函数,因为如果不构造的话,就不能称之为一个对象。而 malloc只是机械的分配一块内存,如果用mallco在堆区创建一个对象的话,是不会调用构造函数的。

例如,我们用如下语法来为一个数组分配空间:

char* pvalue  = NULL;   // 初始化为 null 的指针
pvalue  = new char[20]; // 为变量请求内存

使用完毕后需要删除上面创建的数组:

delete[] pvalue;        // 删除 pvalue 所指向的数组

二维数组:

int **array
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i < m; i++ ) {
    array[i] = new int [n];
}

// 释放空间
for( int i=0; i < m; i++ ) {
    delete[] arrar[i];
}
delete[] array;

这里注意在释放时要先对数组中的所有“行”进行释放,而且要用释放数组的关键字delete[],最后再释放本体。

内存泄漏

内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。内存泄漏带来的后果可能是不严重的,有时甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。

当系统所有的内存全部耗完后(包括主内存和虚拟内存,在嵌入式系统中,仅有主内存),所有申请内存的操作将失败。这通常导致程序试图申请内存来终止自己,或造成分段内存访问错误(segmentation fault)。

以下例子中,存储了整数123的内存空间不能被删除,因为地址丢失了。这些空间已无法再使用。

int main() { 
   int *a = new int(123);
   cout << *a << endl;
   // We should write "delete a;" here
   a = new int(456);
   cout << *a << endl;
   delete a;
   return 0;
}

如果new分配内存失败,会抛出bad_alloc异常,但如果我们使用时在后面加上nothrow关键词,则会返回一个空指针。

RAII

RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。

堆栈溢出

堆栈溢出(stack overflow)在计算机科学中是指使用过多的存储器时导致调用堆栈产生的溢出。堆栈溢出的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆栈溢出很可能由无限递归(Infinite recursion)产生,比如:

int foo(){
    return foo();
}

但也可能仅仅是过多的堆栈层级。


Comments

Content