new,malloc区别的深度解析

Posted 浩瀚之水_csdn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了new,malloc区别的深度解析相关的知识,希望对你有一定的参考价值。

1.  关键字、操作符与库函数

  • 关键字是编译器保留的文字,不能被用户拿来重新声明,像const, new, if等等
  • 操作符必须要有操作对象,操作符本质上可以视为编译器内置的基础的函数。操作符在c++中,可以被重载(除了部分例外,比如 . :: sizeof)。
  • 库函数是编写在编译器头文件库里,要包含头文件才能调用的封装函数。

2. 自由存储区与堆的区别

堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。我们所需要记住的就是:

堆是操作系统维护的一块内存,而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。堆与自由存储区并不等价。 

3. 野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。 

4. malloc和new区别

在C++中,申请动态内存与释放动态内存用new/delete 与 malloc/free都可以,new/malloc申请动态内存,操作系统无法自动回收,需要对应的delete/free释放空间。

  • malloc/free 是c语言中的库函数,需要头文件支持;而new/delete 是c++中的关键字
  • 使用new操作符时编译器会根据类型信息自行计算所需要的内存,而malloc需要显式指出所需内存的尺寸
int *p = new int[2];
int *q = (int *)malloc(2*sizeof(int));
  • malloc内存分配成功时,返回的是void*,需要转换成所需要的类型

    new内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符

    free释放内存的时候需要的是void* 类型的参数

    delete释放内存的时候需要使用具体类型的指针

  • new操作符在分配失败的时候会抛出bac_alloc异常

    malloc在分配内存失败时返回NULL

  • new操作符从自由存储区(free store)上为对象动态分配内存空间,允许重载new/delete操作符

    malloc函数从堆上动态分配内存,malloc不允许被重载

  • new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。

    malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。

5. new()和new[]的区别

  •   new()创建一个对象
  •   new[]创建一个动态数组
  • 释放方法也不一样,new()对应delete,new[]对应delete[]
char *pc = new char('a'); //开辟一个内存单元,并用括号里的初始化
char *pca = new char[15]; //开辟一个数组
释放内存的方法也不一样:
delete pc;
delete []pc;

6delete和delete[]的区别

 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[],其实要分基本数据类型和自定义数据类型。

  • 基本数据类型

int *a = new int[10];

...

delete a;    // 方式1

delete [ ] a;    //方式2

基本的数据类型对象没有析构函数,并且new 在分配内存时会记录分配的空间大小,则delete时能正确释放内存,无需调用析构函数释放其余指针。因此两种方式均可。

  • 自定义数据类型 
#include <iostream>;
using namespace std;
 
class T {
public:
  T() { cout << "constructor" << endl; }
  ~T() { cout << "destructor" << endl; }
};
 
int main()
{
  const int NUM = 3;
 
  T* p1 = new T[NUM];
  cout << hex << p1 << endl;      //输出P1的地址
  //  delete[] p1;
  delete p1;
 
  cout << endl;
 
  T* p2 = new T[NUM];
  cout << p2 << endl;             //输出P2的地址
  delete[] p2;
 
  return 0;
}

从运行结果中我们可以看出,delete p1 在回收空间的过程中,只有 p1[0] 这个对象调用了析构函数,其它对象如 p1[1]、p1[2] 等都没有调用自身的析构函数,这就是问题的症结所在。如果用 delete[],则在回收空间之前所有对象都会首先调用自己的析构函数。
    基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。
    所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。 

 7. delete或者free之要将指针指为NULL

delete和free被调用后,内存不会立即回收,指针也不会指向空,delete或free仅仅是告诉操作系统,这一块内存被释放了,可以用作其他用途。但是由于没有重新对这块内存进行写操作,所以内存中的变量数值并没有发生变化,这时候就会出现野指针的情况。因此,释放完内存后,应该把指针指向NULL
 

#include <iostream>
using namespace std;
 
int main()
{
	int *p = new int;
	*p = 3;
	cout << *p << endl;
	cout << p << endl;
	delete p;
	cout << *p << endl;
	cout << p << endl;
	return 0;
}

 delete之后,p指向的地址并没有发生变化,而地址里面的内容却成了随机数,那么,我们可以得到下面这条结论

我们在删除一个指针之后,编译器只会释放该指针所指向的内存空间,而不会删除这个指针本身。
此时p也就成为一个野指针

#include <iostream>
using namespace std;
 
int main()
{
	int *p = new int;
	delete p;
	p = NULL;
	delete p;
}

如果不加p=NULL;程序运行时就会挂掉,加上就不会了,对NULL空间多次释放时没有问题的,但是不是NULL就不可以,因为这段空间已经释放掉,不属于本程序,不能够取随意的释放。

8. 使用原则

  • 原则1: 优先使用new,delete
  • 原则2: 要new和delete配对,new[]和delete [],malloc和free配对使用
  • 原则3: free和delte后指针一定赋予NULL,防止成为野指针

参考文献:

  1. 关键字、操作符与库函数01
  2. 自由存储区和堆的区别
  3. new 和 malloc free 和 delete 的区别
  4. C++中的delete和delete[ ]的区别
  5. C++中delete和delete[]的区别 - charley_yang - 博客园
  6. C/C++动态内存管理malloc/new、free/delete的异同
  7. delete一个指针之后,要记得设置为NULL
  8. delete或者free之后为什么要将指针指为NULL

以上是关于new,malloc区别的深度解析的主要内容,如果未能解决你的问题,请参考以下文章

经典问题解析四(四十六)

new delete和mallocfree的解析及区别

C++动态内存常见面试题解析

第五十五课经典问题解析四

经典问题解析四

浅谈new/delete和malloc/free的用法与区别