new/delete 和malloc/free 的区别和联系

一、基本概念

     malloc/free:

1、函数原型及说明:

     void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。
     void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

2.内存操作:

     malloc函数的参数是接受需要分配的内存字节数,如果内存能够满足请求量,那么将会返回:指向被分配的内存块起始位置

    free函数释放的是指针指向的内存(不是释放的指针本身,不会删除指针本身),其中指针必须指向所释放内存空间的首地址

 

new/free:

1.操作时发生事件:

    new的时候会有两个事件发生:1).内存被分配(通过operator new 函数)  2).为被分配的内存调用一个或多个构造函数构建对象

    delete的时候,也有两件事发生:1).为将被释放的内存调用一个或多个析构函数  2).释放内存(通过operator delete 函数)

2.特殊应用:

   使用delete是未加括号,delete便假设删除对象是单一对象。否则便假设删除对象是个数组

   因此,如果在调用new时使用了[],则在调用delete时也使用[],如果你在调用new的时候没有[],那么也不应该在调用时使用[]。

 

二、malloc/free 和new/delete 的本质区别:

1.malloc/free是C/C++语言的标准库函数,new/delete是C++的运算符

2.new能够自动分配空间大小

3.对于用户自定义的对象而言,用maloc/free无法满足动态管理对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++需要一个能对对象完成动态内存分配和初始化工作的运算符new,以及一个能对对象完成清理与释放内存工作的运算符delete---简而言之 new/delete能进行对对象进行构造和析构函数的调用进而对内存进行更加详细的工作,而malloc/free不能。

 

三、联系

既然new/delete的功能完全覆盖了malloc/free,为什么C++还保留malloc/free呢?因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。如果用free释放“new创建的动态对象,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存,理论上讲程序不会出错,但是该程序的可读性很差。所以new/deletemalloc/free必须配对使用。

 

四、使用范例

 

void * malloc(size_t size);

用malloc 申请一块长度为length 的整数类型的内存,程序如下:

int *p = (int *)malloc(sizeof(int) * length);

我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。

1. malloc 返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。


下面是对 new/delete 的用法的总结:

一 数组和new

 

数组类型变量三个重要限制:

1 数组长度不变

2 在编译时必须知道其长度

3 数组只在定义它的块语句内存在

突破数组的限制

针对2 需要在运行时动态的分配数组

针对3 动态分配的数组一直存在,直到程序显示释放它

 

自由存储区:又叫做堆。每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区或堆。

C语言使用一对标准库函数:malloc和free

C++则使用new和delete

 

1  动态数组的定义

int *p = new int [10]; //array of 10uninitialized ints

返回指向数组第一个元素的指针,此返回值初始化了指针 p,但是数组内的元素没有初始化,因为内置类型int型没有默认构造函数,如要初始化,在后面加一个括号即可:

int *p = new int [10](); //array of 10uninitialized ints

 

在自由存储区中创建数组对象是没有名字的,程序员只能通过其地址间接的访问堆中对象

 

2 初始化动态分配的数组

string *psa = new string [10];

注意:这里分配了对象的内存空间后,将调用string类型的默认构造函数一次初始化数组中的每个函数

 

int *pia2 = new int [10](); //array of 10initialized ints

可以在数组长度分配一对空括号,对数组元素做值初始化。圆括号要求编译器对数组做值初始化。

i nt *pia2 = new int [10](); 等同于int *pia2= new int [10](0);

动态分配的数组全部被初始化为0

 

3  const 对象的动态数组

const int *pci_ok = new const int [100]();

const string *pci = new const string[100];

当然,创建常量元素不予续修改

 

4允许动态分配空数组

原因:编译时不知道数组的长度,编写一下代码:

      size_tn = get _size();

      int  *p= new int [n];

如果get_size 返回 0 ,怎么办?

答案是:代码仍然正确执行

C++虽然不允许定义长度为0的数组,但是明确指明调用new动态创建长度为0 的数组时合法的。

char arr[0];//error

int *p = new char [0];

 

5 动态空间的释放

delete[]表示释放指针所指向的数组空间

delete [] pia;

方括号:如果漏了空方括号对,编译器无法发现错误,但是导致少释放了内存空间,产生内存泄漏,严重的运行错误等

 

二 对象和new

 

定义变量时,必须指定其数据类型和名字。而动态创建时,只需指定其数据类型,而不必为该对象命名。

int i ;

int *p = new int;

 

1 动态创建对象的初始化

int i(1024);

int *pi = new int(1024);

 

string s(10,’9’);

string *ps = new string(10, ‘9’);

 

2 动态创建对象的默认初始化

对于类类型的对象,用该类的默认构造函数初始化

string *ps = new string ;

内置类型的对象则无初始化

int *pi = new int ;

 

通常,除了对其复制之外,对未初始化的对象所关联的值的任何使用都没有定义的。

对动态创建的对象做值的初始化

 

string *ps = new string(); //initialized toempty string

int *pi = new int (); //pi points to an intvalue-initialized to 0;

cls *pc = new cls(); //pc points to avalue-initialized of type cls

 

对于提供了默认构造函数的类类型string,没有必要对其对性进行值的初始化:无论程序是明确的不初始化哈市要求进行值初始化,都会自动调用其默认构造函数初始化该对象。

 

3耗尽内存

New失败,系统将抛出名为bad_alloc的异常

 

4 撤销动态创建的对象

delete pi;

 

5 0指针的删除

int *ip = 0;

delete ip;

删除0指针式安全

 

6 在delete之后重设指针的值

执行语句

delete p;后,p变成没有定义。

在很多机器上,尽管p没有定义,但仍然存放了它之前所指向对象的地址,然而p所指向的内存已经已经被释放,因此p不再有效。

 

删除指针后,该指针变成悬垂指针。

悬垂指针 :指向曾经存放对象的内存,但该对象已经不再存在了。

悬垂指针往往导致程序的错误,而且很难检测出来

 

注意: 一旦删除了指针所指向的对象,立即将指针置0,这样就非常清楚的表明指针不再指向任何对象。

 

7 const 对象的动态分配和回收

const int *pci = new const int(1024);

与其他常量一样,动态创建的const对象必须在创建时初始化,并且一经初始化,其值就不能再修改。与其他const对象的地址一样,由于new返回的地址上存放的是const对象,因此该地址只能赋给指向const的指针。

 

const string *pcs = new const string ;

 

8 删除const对象

尽管程序员不能够改变const对象的值,但可撤销对象本身。const对象也是使用删除指针来释放的

delete pci;

 

程序错误与动态分配内存分配:

1 删除指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区,删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,等程序运行了一段时间后,耗尽内存空间时,内存泄漏才会显露出来。

 

2 读写已删除的对象。

如果删除指针所指向的对象之后,将指针置为0值,则比较容易检测出这类错误。

 

3 对同一个 内存空间使用两次delete表达式。

当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做delete运算,将该对象的内存空间返还给自由存储区,然后接着delete第二个指针,此时则自由存储区可能会被破坏。

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值