首先总结new/malloc区别:
- new是操作符,malloc是函数
- 是否需要指定内存大小
int* ptr = new a; int* ptr = (int *)malloc(sizeof(int)); new操作符不需指定申请内存大小 malloc必须显示的指出所需内存尺寸
- 内存分配失败时返回值
malloc失败会返回空指针,所以malloc分配后需要判断是否分配成功
new失败会抛异常 - 返回类型
new操作符返回的对象类型的指针,无需进行转换
malloc函数返回void*,需要强制类型转换 - 是否需要调用构造/拷贝函数
- 对数组的处理
int* ptr = new a[10]; delete [] ptr; //必须使用对应的delete [] int* ptr = (int *)malloc(sizeof(int) * 10);
- 是否可以被重载
opeartor new /operator delete可以被重载
malloc/free 无法被重载 - new可以直接初始化,malloc则不行
- new底层通过调用malloc实现的
深入理解:
new的过程:
class A
{
public:
A(int _i)
:i(_i)
{}
private:
int i;
}
A* a = new A(3);可以理解为一下三部:
- 获得一块空间:A* a = (A*)malloc(sizeof(A));
- 调用构造函数(简单变量则被省略):a->A::A(3);
- 返回正确指针:return a;
从效果看,都是获得了一个指向A对象的指针,区别在于使用new时,分配失败会调用new_handler
处理内存分配异常:
operator new的默认行为是请求分配内存,如果成功则返回此内存地址,如果失败则调用一个new_handler
要从operator new的执行过程中返回,则必然需要满足下列条件之一:
- 内存分配成功
- new_handler中抛出bad_alloc异常
- new_handler中调用exit()类似退出函数
void* operator new(size_t size)
{
void* p = null
while(!(p = malloc(size)))
{
if(null == new_handler)
throw bad_alloc();
try
{
new_handler();
}
catch(bad_alloc e)
{
throw e;
}
catch(…)
{}
}
return p;
}
new的三种类型
c++中的new有三种含义:new operator,operator new,placement new
new operator:
new operator就是我们使用的new,行为就是上面所说三个步骤,不能改变
第一步分配内存实际上就是调用operator new,可以重载改变具体的行为
operator new:
这里的new实际上是像加减乘除一样的操作符,因此也是可以重载的。operator new默认情况下首先调用分配内存的代码,尝试得到一段堆上的空间,如
果成功就返回,如果失败,则转而去调用一个new_hander,然后继续重复前面过程
相应的,delete也有delete operator和operator delete之分,后者也是可以重载的。并且,如果重载了operator new,就应该也相应的重载operator delete
这是良好的编程习惯。
placement new:用来实现定位构造
可以实现new operator三步操作中的第二步,也就是在取得了一块可以容纳指定类型对象的内存后,在这块内存上构造一个对象
这有点类似于前面代码中的“p->A::A(3);”这句话,但这并不是一个标准的写法,正确的写法是使用placement new:
#include <new.h>
void main()
{
char s[sizeof(A)];
A* p = (A*)s;
new(p) A(3); //p->A::A(3);
p->Say();
}
对头文件<new>或<new.h>的引用是必须的,这样才可以使用placement new。这里“new(p) A(3)”这种奇怪的写法便是placement new了,它实现了在指定内存地址上用指定类型的构造函数来构造一个对象的功能,后面A(3)就是对构造函数的显式调用
我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数;而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序