background image

   }
};

A* a = new A();

这里通过::operator new 调用了原有的全局的 new,实现了在分配内存之前输出一句

话全局的 operator new 也是可以重载的,但这样一来就不能再递归的使用 new 来分配内
存,而只能使用 malloc 了:
void* operator new(size_t size)
{
   printf("global newn");
   return malloc(size);
}

相应的,delete 也有 delete operator 和 operator delete 之分,后者也是可以重载的

并且,如果重载了 operator new,就应该也相应的重载 operator delete,这是良好的编
程习惯

new 的第三种形态 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)就是对构造函数的显式调用这里不难
发现,这块指定的地址既可以是栈,又可以是堆,placement 对此不加区分但是,除非
特别必要,不要直接使用 placement new ,这毕竟不是用来构造对象的正式写法,只不
过是 new operator 的一个步骤而已使用 new operator 地编译器会自动生成对 placement 
new 的调用的代码,因此也会相应的生成使用 delete 时调用析构函数的代码如果是像上
面那样在栈上使用了 placement new,则必须手工调用析构函数,这也是显式调用析构
函数的唯一情况:
p->~A();

当我们觉得默认的 new operator 对内存的管理不能满足我们的需要,而希望自己手

工的管理内存时,placement new 就有用了 STL 中的 allocator 就使用了这种方式,借助
placement new 来实现更灵活有效的内存管理
处理内存分配异常