3358www.Sina.com/(1) malloc/free是c语言的库函数,new/delete是c的运算符。 运算符可以重载,但不能库函数。
)2)都可以在堆上申请动态内存和释放内存。
)3)内部数据类型是编译器原本就认识到的,不需要用户自己定义。 例如,int、char、double等。 内部以外的数据类型不是编译器本来就识别的,要使编译器识别,需要用户自己定义。 例如,class myclass{…}
)4)对于非内部数据类型,Malloc/free不能满足动态对象的要求。 这是因为对象在创建时运行构造函数,而对象在消亡时运行析构函数。 malloc/free是库函数,因此不在编译器的控制权限之内,不能自动实现构造函数和析构函数。
# includeiostreamusingnamespacestd; 类对象{ public :对象(} { cout ' object ) }构造函数) endl; }~OBJECT () cout ) }~OBJECT ) )析构函数(endl; }; void Use_malloc_free () {cout为malloc/free' endl; object*p=(object* ) malloc ) sizeof ) object ); free(p; }void Use_new_delete () {cout为new/delete' endl; 对象* p=新对象; delete p; }int main () {Use_new_delete ); 在new/delete上创建和销毁对象cout------------'endl的Use_malloc_free (; 在malloc/free中创建和销毁对象return 0; }执行结果:
使用new/deleteOBJECT (构造函数)~OBJECT (构造函数),可以看到使用malloc/free时,对象的结构、构造函数并没有自动运行。
简单来说,malloc只能分配存储器,new可以分配存储器,也可以构造对象的free可以只释放存储器,delete可以释放存储器和析构函数。
malloc/free无法管理动态对象的内存。 应该使用new/delete。 “内部数据类型”没有析构函数和构造函数,在这种情况下等效于使用两者。
注意:由于c程序经常调用c函数,所以malloc/free仍然在使用。
http://www.Sina.com/http://www.Sina.com /
new运营商从自由存储上向对象动态地分配存储器; malloc为堆动态分配内存。
自由存储是c基于new算子的抽象概念。 堆是操作系统上的术语,是操作系统维护的特殊内存。
自由存储区可以是堆或静态存储区,这取决于operator new为对象分配内存的位置。
new还有一个变体。 通过定位new,您可以指定吸引人的耳机使用的位置(地址)。 也就是说,new运算符提供要使用的地址。
定位new运算符存在于头文件中。 定位new只需返回传入的地址并强制将其转换为void*,即可分配给任何指针类型。
# includeiostreamusingnamespacestd; int main () {char buffer[100]; //缓冲器cout ' buffer [ 100 ] address=' (void * ) buffer endl; cout endl; int* p1=new int[10]; //常规new运算符for(intI=0; i 10; I ) (P1 ) I )=10-I; }cout 'p1 address=' p1 endl; cout 'p1[0]=' p1[0] endl; cout endl; int* p2; P2=new(buffer ) int[10]; //new运算符cout 'p2 address=' p2 endl; for(intI=0; i 10; I ) (P2 ) I )=I; }cout 'p2[0]=' p2[0] endl; //p2地址的值也是缓冲器起始地址的值cout endl; int* p3; P3=新(缓冲区) int; newcout 'p3 address=' p3 endl; *p3=
10;//将buffer首地址位置的数值改为10cout << "*p3=" << *p3 << endl;cout << endl;int* p4;p4 = new(buffer + 2 * sizeof(int))int;cout << "p4 address=" << p4 << endl;//偏移10个int字节的新地址cout << endl;return 0;}运行结果
buffer[100] address=008FFC80p1 address=00C50580p1[0]=10p2 address=008FFC80p2[0]=0p3 address=008FFC80*p3=10p4 address=008FFC88p1的地址和buffer不一样,这是因为p1是新开辟的地址。
p2和buffer地址一样,这就是定位new的作用,可以看到p2的起始地址(即buffer的起始地址)的值为0
p3和buffer地址也一样,但是我们改变了数值大小,为10。
p4是相对于buffer偏移了2*4个字节,即8个字节。
关于定位new的隐患:
#include <iostream>using namespace std;class A{public:A(){cout << "creat!" << endl;}~A(){cout << "destory!" << endl;}};int main(){char buffer[100];A *a = new(buffer) A;return 0;}输出
creat!并没有调用析构函数
加上如下代码
输出如下
creat!destory!此处不能使用delete a;原因我还在想。
类在释放自己的空间前,会自动调用析构函数,但是在定位new这里,不能通过delete 语句释放对象,所以,对象就不能隐式的调用析构函数,需要在buffer释放前,显式的调用析构函数。
(2)返回类型安全性
new操作符内存分配成功后,返回的时对象类型的指针,类型严格与对象匹配,无须进行转换,所以new是符合安全类型的操作符。
malloc内存分配成功返回的是void*,需要强制转换成我们所需要的类型。
(3)内存分配失败的返回值
new内存分配失败后,会抛出bac_alloc异常,不会返回NULL;而malloc内存分配失败会返回NULL。
C语言
C++语言
try{ int *a = new int();}catch (bad_alloc){ ...}(4)是否需要指定内存大小
new操作符申请内存不需要指定内存块的大小,编译器会根据类型自动计算;而malloc必须要显示的指出所需内存的大小。
(5)是否调用析构函数/构造函数
使用new操作符来分配对象内存会经历三个阶段:
①调用operator new函数(数组为operator new[])分配一块足够大的、原始的、未命名的内存,一边存储特定类型的对象。
②编译器调用构造函数来构造对象,并传入初值。
③对象构造完毕后,返回该对象的指针。
使用delete来释放对象内存会经历两个步骤
①调用对象的析构函数
②编译器调用operator delete(或者operator delete[])函数释放空间。
然而malloc/free并不会这样,具体上面第1条刚讲过。
(6)对数组的处理
C++提供了new[]和delete[]来专门处理数组
A * ptr = new A[10];//分配10个A对象delete [] ptr;至于malloc,它并不知道你要在这块内存上放的是什么(数组还是单个整形变量),它只会给你一块原始内存以及它的地址;具体想要什么样的你自己去实现。例如:
int * ptr = (int *) malloc( sizeof(int)* 10 );//分配一个10个int元素的数组(7)new和malloc是否可以相互调用
operator new / operator delete的实现可以基于malloc,而malloc的实现不能去调用new。
如下:一种简单实现
(8)是否可以重载
opeartor new /operator delete可以被重载。标准库是定义了operator new函数和operator delete函数的8个重载版本:
我们可以自定义上面版本的任何一个,前提是自定义版本必须位于全局作用域或者类内部。
然而malloc/free不支持重载。
(9)能够再重新分配内存
使用malloc分配内存之后发现内存不足,可以使用realloc函数进行内存的重新分配。
realloc函数先判断当前指针是否有足够的连续空间,如果有,原地扩大内存地址,并返回原来的地址指针;如果空间不够,就重新找到满足新指定大小的内存,分配空间,再将原有数据从头到尾拷贝到新的内存区域,再释放原来的内存区域。
new没有这样的操作。
(10)客户处理内存分配不足
malloc没有这样的功能。
在operator new无法满足某一个内存分配的需求的时候,它会抛出一个异常,在这之前,它会先调用一个客户制定的错误处理函数new_handler。为了指定这个来处理内存不足的函数,使用者需要调用标准库程序函数set_new_handler:
set_new_handler实际上就是一个形参和返回值类型都是new_handler的函数。
具体如下:
如果不能为operator new分配所需要的100000000个整数的空间,outOfMem就会被调用,于是程序终止(abort)。如果一直不能满足的话,outOfMem也就是之前所说的new_handler函数会不断被调用。
那么如何设计一个良好的new_handler:
①让更多的内存被使用。这样做的目的很简单,就是为了内存能够尽可能被operator new进行分配。实现此要求的做法是,当new_handler被调用的时候,将之前分配的内存释放给程序,以便能够继续使用。
②安装新的new_handler。如果当前的new_handler无法取得更多的内存,那么这个new_handler应该能够安装新的new_handler以便能够获得更多的内存空间。
③卸载new_handler,也就是将null指针传给set_new_handler。这样的话,一旦没有分配成功,就会抛出异常。
④抛出bad_alloc的异常。这样的异常不会被operator_new捕捉,因此会被传播到内存索求处。
⑤不返回。通常会调用abort或者exit。
细说new与malloc的10点区别
关于set_new_handler的理解