C++ ---释放内存(new和delete)html
C++动态分配和释放内存 @c.biancheng.net/view/206.htmlios
-------------------------------------------------------------------------------------------------程序员
在C语言中,动态分配内存用 malloc() 函数,释放内存用 free() 函数。以下所示:编程
在C++中,这两个函数仍然可使用,可是C++又新增了两个关键字,new 和 delete:new 用来动态分配内存,delete 用来释放内存。
用 new 和 delete 分配内存更加简单:数组
new 操做符会根据后面的数据类型来推断所需空间的大小。
若是但愿分配一组连续的数据,可使用 new[]:安全
用 new[] 分配的内存须要用 delete[] 释放,它们是一一对应的。
和 malloc() 同样,new 也是在堆区分配内存,必须手动释放,不然只能等到程序运行结束由操做系统回收。为了不内存泄露,一般 new 和 delete、new[] 和 delete[] 操做符应该成对出现,而且不要和C语言中 malloc()、free() 一块儿混用。
在C++中,建议使用 new 和 delete 来管理内存,它们可使用C++的一些新特性,最明显的是能够自动调用构造函数和析构函数,后续咱们将会讲解。函数
--------------------------------------------------------------------------------------------------------------ui
数组的长度是预先定义好的,在整个程序中固定不变。C++ 不容许定义元素个数不肯定的数组。例如:this
可是在实际的编程中,每每会出现所需的内存空间大小取决于实际要处理的数据多少,而实际要处理的数据数量在编程时没法肯定的状况。若是老是定义一个尽量大的数组,又会形成空间浪费。况且,这个“尽量大”到底应该多大才够呢?
为了解决上述问题,C++ 提供了一种“动态内存分配”机制,使得程序能够在运行期间,根据实际须要,要求操做系统临时分配一片内存空间用于存放数据。此种内存分配是在程序运行中进行的,而不是在编译时就肯定的,所以称为“动态内存分配”。
在 C++ 中,经过 new 运算符来实现动态内存分配。new 运算符的第一种用法以下:spa
T *p = new T;
其中,T 是任意类型名,p 是类型为 T* 的指针。
这样的语句会动态分配出一片大小为 sizeof(T) 字节的内存空间,而且将该内存空间的起始地址赋值给 p。例如:
第二行动态分配了一片 4 个字节大小的内存空间,而 p 指向这片空间。经过 p 能够读写该内存空间。
new 运算符还有第二种用法,用来动态分配一个任意大小的数组:
T *p =new T[N];
其中,T 是任意类型名,p 是类型为 T* 的指针,N 表明“元素个数”,能够是任何值为正整数的表达式,表达式中能够包含变量、函数调用等。这样的语句动态分配出 N × sizeof(T) 个字节的内存空间,这片空间的起始地址被赋值给 p。例如:
最后一行编译时没有问题,但运行时会致使数组越界。由于上面动态分配的数组只有 100 个元素,pn[100] 已经不在动态分配的这片内存区域以内了。
若是要求分配的空间太大,操做系统找不到足够的内存来知足,那么动态内存分配就会失败,此时程序会拋出异常。关于这一点,将在后续章节中介绍。
程序从操做系统动态分配所得的内存空间在使用完后应该释放,交还操做系统,以便操做系统将这片内存空间分配给其余程序使用。C++ 提供 delete 运算符,用以释放动态分配的内存空间。delete 运算符的基本用法以下:
delete p;
p 是指向动态分配的内存的指针。p 必须指向动态分配的内存空间,不然运行时极可能会出错。例如:
上面的第一条 delete 语句正确地释放了动态分配的 4 个字节内存空间。第二条 delete 语句会致使程序出错,由于 p 所指向的空间已经释放,p 再也不是指向动态分配的内存空间的指针了。
若是是用 new 的第二种用法分配的内存空间,即动态分配了一个数组,那么释放该数组时,应以以下形式使用 delete 运算符:
delete[] p;
p 依然是指向动态分配的内存的指针。例如:
一样地,要求被释放的指针 p 必须是指向动态分配的内存空间的指针,不然会出错。
若是动态分配了一个数组,可是却用delete p
的方式释放,没有用[]
,则编译时没有问题,运行时也通常不会发生错误,但实际上会致使动态分配的数组没有被彻底释放。
牢记,用 new 运算符动态分配的内存空间,必定要用 delete 运算符释放。不然,即使程序运行结束,这部份内存空间仍然不会被操做系统收回,从而成为被白白浪费掉的内存垃圾。这种现象也称为“内存泄露”。
若是一个程序不停地进行动态内存分配而老是没有释放,那么可用内存就会被该程序大量消耗,即使该程序结束也不能恢复。这就会致使操做系统运行速度变慢,甚至没法再启动新的程序。可是,只要从新启动计算机,这种状况就会消失。
编程时若是进行了动态内存分配,那么必定要确保其后的每一条执行路径都能释放它。
另外还要注意,释放一个指针,并不会使该指针的值变为 NULL。
---------------------------------------------------------------------------------------
一般定义变量或者对象,编译器在编译时均可以根据该变量或对象的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配肯定的存储空间,这种内存分配被称为静态存储分配。
有些操做对象只有在程序运行时才能肯定,这样编译器在编译时就没法为他们预约存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态内存分配。
全部动态存储分配都在堆区中进行。
内存的分配与释放
当程序运行到须要一个动态分配的变量或对象,必须向系统申请取得堆中的一块所需大小的存储空间,用于存储该变量或对象。当再也不使用该变量或对象时,也就是它生命结束之时,要显式释放它所占用的存储空间,这样系统就能对该堆空间进行再分配,作到重复使用有限资源。
在C++中,申请和释放堆中分配的存储空间,分别使用new和delete的两个运算符来完成,使用格式以下:
指针变量名 = new 类型名(初始化式)
delete指针名
new运算符返回的是一个指向所分配类型变量(对象)的指针。对所建立的变量或对象,都是经过该指针来间接操做的,而动态建立的对象自己没有名字。
#include<iostream>
using namespace std; class ST { private: int a; public: ST(int _a=0):a(_a) { this->a = _a; cout<<"Object was built. "<<endl; } ~ST() { cout<<"Object was free. "<<endl; } }; void malloc_free() { ST *tmp = (ST*)malloc(sizeof(ST)); free(tmp); } void new_delete() { ST *tmp = new ST[1];//可是new为对象数组分配空间不可初始化 delete []tmp; } void main() { ST *pt = new ST(1);//new为对象分配空间就可初始化 delete [] pt;//delete p 是删除pt所指空间,而并不是删除pt,为了预防野指针可将pt=NUll malloc_free(); new_delete(); }
运行结果
malloc&free,new&delete都是申请释放空间,可是,有以下几点不一样
1.new申请时不须要强制转换类型,也不须要申请结束后判断是否申请到(由于其内部含有未申请到异常退出)
2.new在为某个对象申请空间时,会调用构造函数,所以可在申请时初始化(对象的构造函数要支持),delete也会在释放空间时会先调用析构函数
3.由堆区建立对象数组(例如ST*pt = new ST[10]),只能调用缺省的构造函数(缺省构造函数:不含参数的或每一个参数都有默认值的构造函数),不能调用其余任何构 造函数。若没有缺省的构造函数则不能建立对象数组。还有,建立对象数组时不能够初始化。
4.对数组进行动态分配格式以下:
指针变量名 = new 类型名[下标表达式]
(下标表达式不是常量表达式,可没必要再编译时肯定)
delete []指向该数组的指针变量名
这二者必须搭配使用,若delete未加[],编译器会认为该指针是指向数组的第一个元素的指针,仅仅回收第一个元素所占空间。加上[]则会回收整个数组。
@https://www.cnblogs.com/area-h-p/p/10339599.html
-------------------------------------------------------
new 和 delete 是 C++ 用于管理堆内存的两个运算符,对应于C语言中的 malloc 和 free,可是 malloc 和 free 是函数,而new 和 delete 是运算符。除此以外,new 在申请内存的同时,还会调用对象的构造函数,而 malloc 只会申请内存;一样,delete 在释放内存以前,会调用对象的析构函数,而 free 只会释放内存。C++new运算符申请内存:将调用相应的 operator new(size_t) 函数动态分配内存,在分配到的动态内存块上 初始化 相应类型的对象(构造函数)并返回其首地址。若是调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。delete运算符释放内存:调用相应类型的析构函数,处理类内部可能涉及的资源释放,调用相应的 operator delete(void *) 函数。int main(){ T * t = new T(); // 先内存分配,再构造函数 delete t; // 先析构函数,再内存释放 return 0;}new表达式type * p_var = new type; //分配内存,但未初始化int * a = new int; type * p_var = new type(init);//分配内存时,将 *a 初始化为 8int * a = new int(8);type *p_var = new type [size]; //分配了3个int大小的连续内存块,但未初始化int * a = new int[3] ; delete表达式删除单变量地址空间int *a = new int;delete a;//释放单个int的空间删除数组空间int *a = new int[5];delete []a;//释放int数组空间C内存区域能够分为栈,堆,静态存储区和常量存储区。局部变量,函数形参,临时变量都是在栈上得到内存的,它们获取的方式都是由编译器自动执行的。而C标准函数库提供了许多函数来实现对堆上内存管理,其中包括:malloc函数,free函数,calloc函数和realloc函数。使用这些函数须要包含头文件stdlib.h。(1)malloc函数malloc函数能够从堆上得到指定字节的内存空间,其函数声明以下:void * malloc(int n);其中,形参n为要求分配的字节数。若是函数执行成功,malloc返回得到内存空间的首地址;若是函数执行失败,那么返回值为NULL。因为malloc函数值的类型为void型指针,所以,能够将其值类型转换后赋给任意类型指针,这样就能够经过操做该类型指针来操做从堆上得到的内存空间。须要注意的是,malloc函数分配获得的内存空间是未初始化的。所以,通常在使用该内存空间时,要调用另外一个函数memset来将其初始化为全0。memset函数的声明以下:void * memset (void * p,int c,int n) ;该函数能够将指定的内存空间按字节单位置为指定的字符c。其中,p为要清零的内存空间的首地址,c为要设定的值,n为被操做的内存空间的字节长度。int * p=NULL;p=(int *)malloc(sizeof(int));if(p==NULL){ printf(“Can’t get memory!\n”);}memset(p,0,siezeof(int));(2)free函数从堆上得到的内存空间在程序结束之后,系统不会将其自动释放,须要程序员来本身管理。一个程序结束时,必须保证全部从堆上得到的内存空间已被安全释放,不然,会致使内存泄露。void free (void * p);因为形参为void指针,free函数能够接受任意类型的指针实参。可是,free函数只是释放指针指向的内容,而该指针仍然指向原来指向的地方,此时,指针为野指针,若是此时操做该指针会致使不可预期的错误。安全作法是:在使用free函数释放指针指向的空间以后,将指针的值置为NULL。free(p);p=NULL;//注:使用malloc函数分配的堆空间在程序结束以前必须释放(3)calloc函数calloc函数的功能与malloc函数的功能类似,都是从堆分配内存。其函数声明以下:void *calloc(int n,int size);函数返回值为void型指针。若是执行成功,函数从堆上得到size X n的字节空间,并返回该空间的首地址。若是执行失败,函数返回NULL。该函数与malloc函数的一个显著不一样时是,**calloc函数获得的内存空间是通过初始化的,其内容全为0。**calloc函数适合为数组申请空间,能够将size设置为数组元素的空间长度,将n设置为数组的容量。 int * p=NULL;//为p从堆上分配SIZE个int型空间p=(int *)calloc(SIZE,sizeof(int));if(NULL==p){ printf("Error in calloc.\n"); return -1;}free(p);p = NULL;(4)realloc函数realloc函数的功能比malloc函数和calloc函数的功能更为丰富,能够实现内存分配和内存释放的功能,其函数声明以下:void * realloc(void * p,int n);其中,指针p必须为指向堆内存空间的指针,即由malloc函数、calloc函数或realloc函数分配空间的指针。realloc函数将指针p指向的内存块的大小改变为n字节。若是n小于或等于p以前指向的空间大小,那么。保持原有状态不变。若是n大于原来p以前指向的空间大小,那么,系统将从新为p从堆上分配一块大小为n的内存空间,同时,将原来指向空间的内容依次复制到新的内存空间上,p以前指向的空间被释放。relloc函数分配的空间也是未初始化的。 int * p=NULL;p=(int *)malloc(sizeof(int));p=(int *)realloc(p,3*sizeof(int));//释放p指向的空间realloc(p,0);p=NULL;注:使用malloc函数,calloc函数和realloc函数分配的内存空间都要使用free函数或指针参数为NULL的realloc函数来释放。 原文连接:https://blog.csdn.net/dongxianfei/article/details/79031943