我们又了解new多少呢?
关于new操作符,我们在对空间的请求(对于类来说)上一共进行两步:
对于new:先进行空间分配,再进行调用构造函数。
在new与delete中的第二步,实际上都是调用一个全局函数operator new/delete对空间进行分配/回收。
在这个全局构造函数中::operator new 有6个重载,其中有三个是关于数组空间的分配。
如下:
void *operator new(std::size_t count) throw(std::bad_alloc); // 一般的版本
void *operator new(std::size_t count,new const std::nothrow_t&) throw(); // 内存分配失败不会抛出异常
void *operator new(std::size_t count, void *ptr) throw(); <span style="white-space:pre"> </span> //placement 版本 <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
void *operator new[](std::size_t count) throw(std::bad_alloc);
void *operator new[](std::size_t count, const std::nothrow_t&) throw();
void *operator new[](std::size_t count, void *ptr) throw();
对于一般版本,为了兼容早期new而不抛出异常的版本 ,我们已经用的很熟练了,我们只谈一谈placment new 版本。
区分new 操作符与operator new 函数是十分重要的,对于new操作符,我们不可以重载所以new操作符的行为是确定的,而operator new是可以进行重载的,对其进行替换的 。但对于placement new 版本,在c++标准中已经明令禁止我们去重载这个版本,对于其它版本我们可以任意的去替换掉(说是这么说但实际上并不赞同这样做)。
为什么c++严禁我们去重载这个placement new 这个函数呢,palcement new 与其它重载版本不同它实际上并不会分配任何空间,仅仅返回一个可能指向空间的指针。
因此我们不能对placemen newt进行delete操作。
可能有人会问对于placement new有什么作用?
我们在创建一个对象的时候,我们可能不想给它初始化,我们希望迟一点初始化,这时候,而我们提前对它的初始化就是十分浪费效率的。
我们就可以这样做
A *number0 = static_cast<A*>(::operator new(sizeof(A)));
new(number0)A();
对于operator new(size_t);实际上与memory.h头文件中的malloch函数效果是一样的的。
通常对placement new也搭配一些其它操作,一般来说这个是必要的,我们必须对一个类对象进行析构,不过直接对一个对象进行析构十分不妥的,我们需要对这个析构进行一下封装。
实际上,对于一个类而不是语言内嵌类型,对于一个new与delete的操作实际上是分成三步的,多了一步,我们在进行operator new 调用之前会先查找class内是否有这个operator new 的重载,如果有我们会调用class中的重载版本,有一点就算我们把operator new 声明为私有类成员,编译器也只会提示一个类成员不可调用,也不会调用全局的operator new。
我们在开始说placement new 重载是明令禁止的,但这个要求仅限于全局,我们在类中仍可以定义一个“placement new”。
还有一点,对于类内重载的operator new/delete是静态成员函数, 因为他用不到this指针。所以operator new/delete是可以被继承的,
关于数组的说明:
!只有一点
我们对于数组的分配方法
A *number1 = static_cast<A*>(::operator new[](sizeof(A)*2));
A *number2 = new A[2];
第二种相对于第一种可能会略微增加内存。
关于operator new我们可能面临这样一个错误,当我们无法知道一个类是否已经重载operaotr的时候,我们就面临着一个很危险的行为,我们无法准确的对这个类进行异常的判断此时我们必须将所有的operator new都使用全局版本。
一般的来说我们在重载operator new 的时候一般也会重载operator delete 如果一个类的operator new 分配失败则,这个类将调用operator delete 进行回收。