new 和 delete 的执行过程
new 的执行过程
-
通过 operator new 申请内存
-
调用构造函数(简单类型忽略此步)
-
返回内存指针
delete 的执行过程
- 调用析构函数(简单类型忽略此步)
- 释放内存
using namespace std;
class T
{
public:
T()
{
cout << "constructor\n";
}
~T()
{
cout << "deconstructor\n";
}
void * operator new(size_t sz)
{
T* t = (T*)malloc(sizeof(T));
cout << "malloc memory\n";
return t;
}
void operator delete(void* p)
{
free(p);
cout << "free memory\n";
}
};
int main()
{
T* t = new T{};
delete t;
return 0;
}
输出:
malloc memory
constructor
deconstructor
free memory
new/delete 和 delete/malloc 的比较
new 和 malloc 的比较
- new 失败时会调用 new_handler 处理函数,malloc 不会,失败时返回 NULL
- new 能自动调用对象的构造函数,malloc 不会
- new出来的东西是带类型的,malloc 是 void*,需要强制转换
- new 是 C++ 运算符,malloc 是 C 标准库函数
delete 和 free 的比较
- delete 能自动调用对象的析构函数,malloc 不会
- delete 是 C++ 运算符,free 是 C 标准库函数
new 的三种形态
new 的三种形态:
- new operator
- operator new
- placement new
new operator
上面所说的 new 就是 new operator,共有三个步骤组成(申请内存,调用构造函数,返回内存指针)。
- 是 C++ 的操作符。
- 不可以被重载。
operator new
只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则如果有 new_handler,则调用 new_handler,否则如果没要求不抛出异常(以 nothrow 参数表达),则执行 bad_alloc 异常,否则返回 0。
- 是 C++ 库函数。
- 可以被重载
- 重载时,返回类型必须声明为 void*。
- 重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为 size_t。
- 重载时,可以带其它参数。如果重载了 operator new,那么也得重载对应的 operator delete。
- 如果类中没有重载 operator new,那么调用的就是全局的 ::operator new 来完成堆的分配。
placement new
placement new 是重载operator new 的一个标准、全局的版本,它不能够被自定义的版本代替。
声明在头文件 <new>
中,如果想在一块已经获得的内存里建立一个对象,那就应该用 placement new。
placement new 适用于:在对时间要求非常高的应用程序中,因为这些程序分配的时间是确定的;长时间运行而不被打断的程序;以及执行一个垃圾收集器。
Placement new 使用步骤
- 缓存提前分配,有三种方式:
- 在堆上进行分配:
char * buff = new [sizeof(Task)];
- 在栈上进行分配:
char buf[N*sizeof(Task)];
- 直接通过地址来使用,(必须是有意义的地址):
void* buf = reinterpret_cast<void*> (0xF00F);
- 在堆上进行分配:
- 对象的分配,在刚才已分配的缓存区调用placement new来构造一个对象:
Task *ptask = new (buf) Task
。 - 使用,按照普通方式使用分配的对象:
ptask->memberfunction();
. - 对象的析构,一旦你使用完这个对象,你必须调用它的析构函数来毁灭它。按照下面的方式调用析构函数:
ptask->~Task();
- 释放,可以反复利用缓存并给它分配一个新的对象,如果不打算再次使用这个缓存,你可以象这样释放它:
delete [] buf
;
char* ptr = new char[sizeof(T)]; //@ allocate memory
T* tptr = new(ptr) T; //@ construct in allocated storage ("place")
tptr->~T(); //@ destruct
delete[] ptr; //@ deallocate memory