New 的 3 种形态: new operator 、 operator new 、 placement new
new 操作符 (new 表达式 , new operator , new expression): 通常我们调用 X * pX = new X 时使用的就是这个操作符 , 它由语言内建 , 不能重载 , 不能改变其行为 . 它包括分配内存的 operator new 和调用构造函数的 placement new 。 new 关键字实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。当然,如果我们创建的是简单类型的变量,那么第二步会被省略。
operator new : operator new 是一个函数 , void * operator new(size_t size) 。它分配指定大小的内存 , 可以被重载 , 可以添加额外的参数 , 但第一个参数必须为 size_t 。 operator new 除了被 new operator 调用外也可以直接被调用 : void * rawMem = operator new(sizeof(X)) 。这种用法和调用 malloc 一样。
placement new : placement new 在一块指定的内存上调用构造函数 , 包含头文件 <new> 之后也可以直接使用 placement new: X * pX = new (rawMem) X 。
与 new operator 类似 , 对于 delete operator, 也存在 operator delete: void operator delete(void *), 析构方法 pX->~X().
New 的基本使用指南:
想在堆上建立一个对象,应该用 new 操作符。它既分配内存又为对象调用构造函数。如果仅仅想分配内存,就应该调用 operator new 函数;它不会调用构造函数。如果想定制在堆对象被建立时的内存分配过程,你应该写你自己的 operator new 函数,然后使用 new 操作符, new 操作符会调用定制的 operator new 。如果想在一块已经获得指针的内存里建立一个对象,应该用 placement new 。 placement new 主要适用于:在对时间要求非常高的应用程序中,因为这些程序分配的时间是确定的;长时间运行而不被打断的程序;以及执行一个垃圾收集器 (garbage collector) 。
由于 placement new 的特殊性,下面给出其常规使用步骤:
class Task ; //
char * buff = new char[sizeof(Task)]; // 1) 分配内存
Task *ptask = new(buff) Task ; // 2) 构造对象
ptask->suspend(); // 3) 正常使用对象
ptask->resume();
ptask->~Task(); // 4) 析构对象
delete [] buff; // 5) 释放内存
显然, placement new 可以提高效率,但增加了程序的复杂度,需要自行管理对象的生存期。 Placement new 的使用大量存在于 STL 中。