一、为什么需要动态内存分配?
在C++程序中,所有内存需求都是在程序执行之前通过定义所需的变量来确定的。 但是可能存在程序的内存需求只能在运行时确定的情况。 例如,当需要的内存取决于用户输入。 在这些情况下,程序需要动态分配内存,C++语言将运算符new和delete合成在一起【2】。
在C++中申请动态内存与释放动态内存,可以使用new/delete或者malloc/free,它们的储存方式相同;而在C中只能使用malloc/free。
malloc/free是C/C++语言的标准库函数,在C语言中需要头文件<stdlib.h>的支持,new/delete是C++的运算符。对类对象而言,malloc/free无法满足动态对象的要求,对象在创建的同时要自动执行构造函数,对象消亡之前要自动执行析构函数,而malloc/free不在编译器控制权限内,无法执行构造函数和析构函数【1】。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A is here!" << endl;
}
~A()
{
cout << "A is dead!" << endl;
}
private:
int i;
};
int main()
{
A* pA = new A;
delete pA;
return 0;
}
(1)特点
- 1.C++中通过new关键字进行动态内存申请
- 2.C++中的动态内存分配是基于类型进行的
- 3.delete关键字用于内存释放
(2)语法
①变量申请:
Type* pointer = new Type; //type表示数据类型,*pointer:指针,指向内存空间
//...
delete pointer;
表达式用于分配内存以包含一个类型的单个元素。
②数组申请:
Type* pointer = new Type[N];
//...
delete[] pointer;
表示用于分配类型的元素的块(数组),其中N是表示这些元素的量的整数值。
Example:
int * foo;
foo = new int [5];
在这种情况下,系统为int类型的五个元素动态分配空间,并返回指向序列的第一个元素的指针,该指针被分配给foo(指针)。 因此,foo现在指向一个有效的内存块,其中包含五个int类型元素的空间。
这里,foo是一个指针,因此,foo指向的第一个元素可以使用表达式foo [0]或表达式* foo(两者都是等价的)来访问。可以使用foo [1]或*(foo + 1)访问第二个元素,依此类推......
Note:
我们程序请求的动态内存由系统从内存堆中分配。 但是,计算机内存是一种有限的资源,它可能会耗尽。 因此,无法保证所有使用operator new分配内存的请求都将由系统授予。
例子:
#include <iostream>
using namespace std;
void main()
{
int* p = new int; //申请动态内存
*p = 5;
*p = *p + 3;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
delete p; //释放动态内存
p = new int[10];
for (int i = 0; i < 10; ++i)
{
p[i] = i + 1;
cout << "p[" << i << "] = " << p[i] << endl;
}
delete[] p;
}
new/delete与malloc/free
相同点:
- new和malloc动态申请的内存都位于堆中,无法被操作系统自动回收,需要对应的delete与free来释放空间,对于一般的数据类型(int,chat等),它们的效果一样。
- free或者delete调用后,内存并没有释放,指针也不会指向空,还储存有内容,这就出现了野指针的情况,所以在将资源free或delete调用后,还需要将指针置为NULL才行。
new/delete的功能完全覆盖了malloc/free,malloc/free在C++中没被取消是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。所以仍保留了malloc/free。
区别:
- malloc/free需要库文件stdlib.h支持,而new/delete不需要。
- new能调用构造函数,而malloc不能;delete将调用析构函数,而free不能。
- new能够自动计算需要分配的内存空间,而malloc需要手工计算字节数。例如,int* p1 = new int[2]; int * p2 = malloc(2*sizeof(int));
- new与delete直接带具体类型的指针,malloc与free返回void类型的指针
- new一般由两步构成,分别是new操作和构造。new操作对应于malloc,但new操作可以重载,可以自定义内存分配策略,不做内存分配,甚至分配到非内存设备上,而malloc不行。
- new在申请单个类型变量时可以进行初始化,malloc不具备内存初始化的特性。
new关键字的初始化:
int* p1 = new int(1);
float* p2 = new float(2.0f);
char* p3 = new char('c');
#include <iostream>
using namespace std;
int main()
{
int* pi = new int(1); //动态分配一个int,初始化为1
// int* pa = new int[1]; //动态分配一个数组,数组大小为1
float* pf = new float(2.0f);
char* pc = new char('c');
printf("*pi = %d\n", *pi);
printf("*pf = %f\n", *pf);
printf("*pc = %c\n", *pc);
delete pi;
delete pf;
delete pc;
return 0;
}
参考:
【1】:《程序员面试笔试宝典》