背景:
对计算机编程来说,变量和对象在内存中的分配是编译器在编译程序时安排的,给我们带来了很大的不便,比如必须增大和减小数组。 (增大或减小意味着数组容量为100,实际使用10会增加内存浪费。 ) )因此,为了解决这个问题。 我们为了解决这个问题引入了动态内存分配。
一、动态内存的使用方法
因为new返回指针类型,所以必须用相同类型的指针接受。 在某些特殊情况下,继承时可以用父指针指向子类对象。
new和delete运算符是用于动态分配和撤消内存的运算符。
1 .要打开单变量地址空间并使用new运算符,您必须知道数据类型。 new运算符请求系统堆空间的足够存储空间,如果请求成功,则返回该内存块的起始地址;如果请求失败,则返回零值。
new运算符返回指向分配的类型变量(对象)的**指针**。 由于创建的变量或对象是由**指针**间接操作的,因此动态创建的对象本身没有标识符名称。
常用使用格式:
格式1 :指针变量名称=new类型标识符;
格式2 :指针变量名=new类型标识符(初始值);
格式3 :指针变量名=new型识别符[存储单元数]
说明:格式1的写法只是申请空间,不对其赋值进行初始化。
格式2内存分配成功后,同时将初始值存储在其存储单元中,如果只写括号也不写具体值,则默认用0初始化该对象;
在格式3中,可以同时分配多个存储单元,这相当于形成动态数组。
例如:
1 )新建int; 打开保存//整数的存储区域,返回指向该存储区域的地址。 int *a=new int是为整数指针a分配int类型的地址
2 ) int *a=new int(5) 5作用相同,但同时将整数空间代入5
2 .打开一维数组空间对数组动态分配的形式如下:
指针变量名称=new类型名称[下标表达式]
指向delete [ ]数组的指针变量名称;
表达式中的方括号非常重要,必须成对使用两者。 如果delete语句不包含方括号,编译器将该指针识别为指向数组中第一个元素的指针,从而导致回收不完整。 添加方括号将转换为指向数组的指针,并回收整个数组。
不需要在delete []的方括号中键入数组元素的数量。 系统知道。 即使写了也无视编译器。
请注意,“下标表达式”不必是常量表达式。 也就是说,该值在编译时不需要确定,而是可以在运行时确定。
一维:int t; cin t; int* a=new int[t]; //这个一维数组是运行时确定的空间
3 .开拓多维数组的写法和用法。 左半部分:类型名称(*指针名称) [阵列第二次元长度] ) [阵列第三次元长度] ……。
右半部:new类型名称[数组第一维长度][数组第二维长度][数组第三维长度] ……………。
有两个注意事项:
1 .不要忘记左半部分的括号
2 .左大括号中的维度比右边少第一个维度。
int(*p ) [3]=newint ) [2][3]; //二维int(P1 ) [2][3]=newint )1) [2][3]; //三维
4、删除delete用法1 .删除单变量地址空间
int *a=new int;
电传a; //释放各个int的空间
2 .删除数组空间,
int *a=new int[5];
delete []a; 释放//int数组空间。 注意,即使是多次元数组,也只需在最后的delete后面写[]即可。
2 )动态内存分配和我们自定义类相遇时的注意事项。 既然是自定义类,构造函数问题就不可避免。
如果自定义类包含用户定义的默认构造函数,则new T和new T ) )是否加括号是相同的。
但是,如果用户没有定义默认的复制构造函数,此时就会有差异。 使用new T时,将调用系统的隐式构造函数。 另一方面,new T ) )将0赋值给所有基本数据类型和指针类型,而不仅仅是系统的隐式构造函数。 这个过程是递归的,什么是递归? 当一个类包含另一个自定义类型时,所有到该自定义类都用0初始化。
//先给你上课,class point {public: int m_a; int m_b; point (); point () { this-m_a=m_a; this-m_b=m_b; }
void print(int m_a, int m_b) { cout << m_a << " " << m_b << endl; }};1.创建单独类的对象
//调用无参构造函数
point *p=new point;
//调用有参构造函数
point *p=new point(1,3)
2.创建自定义类数组
point* p = new point[10];
point* p = new point[10]();
用法:
point* p = new point[10];
p[1].m_a = 1;
p[1].m_b = 2;
p[1].print();
delete []p;
1. new 和delete都是内建的操作符,语言本身所固定了,无法重新定制,想要定制new和delete的行为,徒劳无功的行为。
2. 动态分配失败,则返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。所以使用时尽量先判断一下(if(指针变量名!=NULL)
3. 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身(指针p本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针。
4. 内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会**重复释放**堆内存空间。(千万小心,别把系统整瘫痪)。
5. 动态分配的变量或对象的生命期。我们也称堆空间为自由空间(free store),但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放,往往会出错。
6. 要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问。
用new和delete可以动态开辟和撤销地址空间。在编程序时,若用完一个变量(一般是暂时存储的数据),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它。