动态对象(堆对象)是程序在运行过程中在动态内存中用new运算符创建的对象。
由于是用户自己用new运算符创建的,因此也要求用户自己用delete运算符释放,即用户必须自己管理动态内存。
计算机内存数据区常有三种分区,即静态数据区、堆区、桟区。
1.程序在编译时就为静态变量和静态对象分配了静态数据存储区。在静态数据区中存储的变量或对象在该程序的整个运行期间都存在,
它们的生命周期贯穿整个程序的运行周期。比如全局变量、static(静态)变量等都是存储在静态数据区。
2.调用函数时,函数内的局部变量和形式参数等将在桟区中分配存储单元。这部分变量的生命周期与函数的执行时间相同。
当函数执行结束时,存储这些变量的存储单元会被自动释放,从而这些变量的生命周期也就结束了。
由于桟区的大小一般很有限,因此能够同时保存在桟区中的变量数量有限。
由于存储在桟区中的变量生命周期短,因此桟区的使用率高很高,可以不断成为新生成变量的存放空间。
3.当执行new运算符时,系统会自动在动态内存空间中分配存储,动态内存位于堆区,它是唯一一个生存期可以由程序员自己控制的存储空间。
程序在运行时程序员可以用new申请动态内存空间,但不用时,程序员必须自己用delete释放这部分空间(释放内存)。
因此,程序在这部分出错的概率极高。
管理动态内存空间的运算符是new和delete,还有new[]与delete[].
C语言中用 malloc()和free()函数申请分配和释放动态内存空间。
C++用new和delete运算符来申请分配和释放动态内存空间。
new运算符可以自动计算所申请空间的大小,而malloc()函数则必须由程序员指出所需申请分配空间的大小。
#include<iostream>
using namespace std;
int main()
{
char *p1;
int *p2;
int *p3=new int (14);
int *p4=new int [3];
p1=new char; //new一个整型数,并将该整型数的地址赋值给p1
p2=new int (10);//new一个初值为200的整型数,并将该整型数的地址赋给p2
*p1=97;
for(int i=0;i<3;i++)
{
cin>>*(p4+i);
}
cout<<*p1<<endl;
cout<<*p2<<endl;
cout<<*p3<<endl;
for(int i=0;i<3;i++)
{
cout<<*(p4+i)<<" ";
}
cout<<endl;
delete p3;
delete p2;
delete p1;
delete []p4;
p1=NULL;
p2=NULL;
p3=NULL;
p4=NULL;
system("pause");
return 0;
}
注意:
1.当系统无法满足动态内存分配>内存分配的请求时他将会返回NULL,所以new执行后必须判断返回的指针值是否为NULL,是则表示动态内存分配>内存分配不成功。
只有返回值是非NULL时,才可继续执行后续的操作。
如果对一个未申请成功的指针进行相关的内存操作将可能引起系统崩溃。
2.delete只能用来释放用new申请分配的动态内存空间;反之,new申请的动态内存空间必须用delete来释放。
delete与new必须有对应的关系。
3.delete执行之后,指针所指向的内存空间就被释放了,而指向该动态内存区域的指针变量本身并不会因为delete有任何改变。
4.delete之后,不对指针变量做任何处理,就会造成“指针悬挂”;
5.指针变量声明后没有进行初始化就通过它操作内存空间,则可能制造一个“野指针”;
6.关于指针和动态内存要特别注意:
指针消亡了,并不代表它所指向的动态内存会被自动释放,自动消亡;
动态内存被释放了,并不代表指向该动态内存的指针变量会消亡或自动变成NULL;
做到以下几点,可以防止错误的发生:
1.定义指针变量的同时初始化。如不初始化就一定要将其设置成NULL,避免该指针指向一个不确定的地方,引发误操作,这是非常危险的。
一旦把它置成NULL,误用它就不会造成太大问题;
2.delete指针以后,第一时间将其设置为NULL。即使是一个马上就要消亡的局部指针变量,也可立即将其置成NULL。养成良好的习惯是避免错误的有效方法;
3.当指针指向数组时,一定谨慎防止指针越界操作;
4.避免用指针传递桟内存,避免返回一个即将自动消亡的局部变量或局部对象的地址。
桟内存中的局部变量和局部对象都不能跨函数生存,要注意它们的生存周期。
注意 delete :
#include<iostream>
using namespace std;
int main()
{
int i,*pi1=&i,*pi2=nullptr;
double *pd=new double (33),*pd2=pd;
int ii=0;
//delete i;//错误,i不是一个指针
cout<<ii++<<endl;
//delete pi1;//为定义:pi1指向一个局部变量,未分配动态内存
cout<<ii++<<endl;
delete pi2;//正确:释放一个空指针
cout<<ii++<<endl;
delete pd;//正确
cout<<ii++<<endl;
//delete pd2;//未定义,:指向的内存已经被释放了
cout<<ii++<<endl;
system("pause");
return 0;
}
对于delete i的请求,编译器会生成一个错误信息,因为它知道i不是一个指针。执行delete pi1和pd2所产生的错误则更具有潜在危害:通常情况下,编译器不能分辨一个指针指向的是静态还有动态分配的对象。同时,编译器也不能分辨一个指针所指向的内存是否已经被释放了。