我们写如下代码:
A* a = new A;
我们知道这里分为三步:1.分配内存,2.调用A()构造对象,3. 返回分配指针。事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),否则调用全局::operator new(size_t ),后者由C++默认提供。因此前面的步骤也就是:
1.调用operator new (sizeof(A))
2.调用A:A()
3.返回指针
new 的功能是 1. 分配空间, 2 调用构造函数。 那么到底是如何实现的呢?
其实 C++ 规定 new 的 这 两个功能分开实现:
1. 分配空间: 调用函数 operator new 来实现。
2. 调用构造函数: 调用 placement new 来实现。
new关键字 会调用 operator new 分配空间: 这里 operator new 是一个全局的函数,写在一个文件中。当使用 new 关键字 的时候,编译器会自动找到这个函数,并且调用这个函数:这个函数的声明如下:
// 全局 operator new
void * operator new(std::size_t size) throw(std::bad_alloc) {
if (size == 0)
size = 1;
void* p;
while ((p = ::malloc(size)) == 0) { //采用 malloc 分配空间
std::new_handler nh = std::get_new_handler();
if (nh)
nh();
else
throw std::bad_alloc();
}
return p;
}
// 对应的全局 operator delete 采用 free 释放空间
void operator delete(void* ptr) {
if (ptr)
::free(ptr); //采用 free 释放空间。
}
这个 operator new
函数称为 全局 operator new 。 (这里称为 全局 主要是因为 每个类 还可以 重载 自己的 operator new()
函数)
全局 operator new 分配空间
从上个例子中可以看到, 全局 operator new 分配空间,简单的调用了 malloc() 函数来分配空间。 并没有做任何初始化工作。
现在问题来了: 已经有了一段分配好的空间 ,如何在这个空间上 调动这个类的构造函数,从而真正的创建一个对象呢?
解决方案是: placement new
placement new 调用构造函数
placement new 的功能就是 在一个 已经分配好的空间上,调用构造函数,创建一个类。
placement new 就这一个用法,知道如何用就可以了,它不是一个(写在文件中)函数,是编译器编译时候做的事情。
用法如下:
void *buf = // 在这里为buf分配内存
Class *pc = new (buf) Class();
举例子:
class A {...} //声明一个 类 A
void *buf = malloc(sizeof(A)); //简单地分配空间。
A *ojb = new (buf)A(); // 在分配的空间上调用构造函数。