首页 > 编程知识 正文

malloc和free的用法,new和delete的用法

时间:2023-05-04 18:42:57 阅读:146407 作者:3906

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=008FFC88

p1的地址和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!

并没有调用析构函数
加上如下代码

a.~A();

输出如下

creat!destory!

此处不能使用delete a;原因我还在想。
类在释放自己的空间前,会自动调用析构函数,但是在定位new这里,不能通过delete 语句释放对象,所以,对象就不能隐式的调用析构函数,需要在buffer释放前,显式的调用析构函数。
(2)返回类型安全性
new操作符内存分配成功后,返回的时对象类型的指针,类型严格与对象匹配,无须进行转换,所以new是符合安全类型的操作符。
malloc内存分配成功返回的是void*,需要强制转换成我们所需要的类型。

(3)内存分配失败的返回值
new内存分配失败后,会抛出bac_alloc异常,不会返回NULL;而malloc内存分配失败会返回NULL。
C语言

int *a = (int *)malloc ( sizeof (int ));if(NULL == a){ ...}else { ...}

C++语言

try{ int *a = new int();}catch (bad_alloc){ ...}

(4)是否需要指定内存大小
new操作符申请内存不需要指定内存块的大小,编译器会根据类型自动计算;而malloc必须要显示的指出所需内存的大小。

class A{...}A * ptr = new A;A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);

(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。
如下:一种简单实现

void * operator new (sieze_t size){ if(void * mem = malloc(size) return mem; else throw bad_alloc();}void operator delete(void *mem) noexcept{ free(mem);}

(8)是否可以重载
opeartor new /operator delete可以被重载。标准库是定义了operator new函数和operator delete函数的8个重载版本:

//这些版本可能抛出异常void * operator new(size_t);void * operator new[](size_t);void * operator delete (void * )noexcept;void * operator delete[](void *0)noexcept;//这些版本承诺不抛出异常void * operator new(size_t ,nothrow_t&) noexcept;void * operator new[](size_t, nothrow_t& );void * operator delete (void *,nothrow_t& )noexcept;void * operator delete[](void *0,nothrow_t& )noexcept;

我们可以自定义上面版本的任何一个,前提是自定义版本必须位于全局作用域或者类内部。
然而malloc/free不支持重载。

(9)能够再重新分配内存
使用malloc分配内存之后发现内存不足,可以使用realloc函数进行内存的重新分配。
realloc函数先判断当前指针是否有足够的连续空间,如果有,原地扩大内存地址,并返回原来的地址指针;如果空间不够,就重新找到满足新指定大小的内存,分配空间,再将原有数据从头到尾拷贝到新的内存区域,再释放原来的内存区域。
new没有这样的操作。

(10)客户处理内存分配不足
malloc没有这样的功能。
在operator new无法满足某一个内存分配的需求的时候,它会抛出一个异常,在这之前,它会先调用一个客户制定的错误处理函数new_handler。为了指定这个来处理内存不足的函数,使用者需要调用标准库程序函数set_new_handler:

namespace std{ typedef void (*new_handler){ };//一个函数指针 new_handler set_new_handler(new_handler p) throw();};

set_new_handler实际上就是一个形参和返回值类型都是new_handler的函数。
具体如下:

void outOfMem(){ std::cerr<<"Unable to statisfy request for memoryn"; std::abort();}int main(){ set_new_handler(outOfMem); int *pBigDataArray=new int[100000000L]; ...}

如果不能为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的理解

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。