C++ new 的基本和高级用法
推荐文章 http://kelvinh.github.io/blog/2014/04/19/research-on-operator-new-and-delete/
new 的基本用法
int *a = new int[5];
class A {...} //声明一个类 A
A *obj = new A(); //使用 new 创建对象
delete []a;
delete obj;
这里我们注意,new int[5] 仅仅分配了空间, 但是 new A(),不仅仅为对象obj在队上分配了空间, 而且还调用了 A的构造函数,生成了这个对象。
所以 new A() 这样方式的功能如下:
- 在堆上分配空间
- 在分配的空间上调用对象的构造函数
(这也是 new 和 malloc的主要区别,是否调用构造函数)
同理: 在调用 delete obj
的时候:
1. 首先调用 这个对象 的析构函数
2. 然后释放这个对象的空间
new 的升级版本 (version 1)
从上面可以看到:new 的功能是 1. 分配空间, 2 调用构造函数。 那么到底是如何实现的呢?
其实 C++ 规定 new 的 这 两个功能分开实现:
1. 分配空间: 调用函数 operator new 来实现。
2. 调用构造函数: 调用 placement new 来实现。
现在有三个 new 了,第一个new就是我们常说的new, 这个new 调用 接下来的两个new 来实现它的功能。 (我们称这个 new 为, new operator,叫做“new 表达式”,因为operator 在 new 后面,所以 叫做 “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(); // 在分配的空间上调用构造函数。
现在问题来了: 这里 的空间可以是任意的空间吗,答案是的! 这里的 “已经分配好的空间” 可以是任何的空间,比如说 可以是栈上的空间!
class A {int a;}
int buf[sizeof(A)]; //在栈上,分配一个数组
A *obj = new(buf) A(); //在这个数组上构造一个 对象 A。
new 的升级版本 (version 2)
我们称上一个 operator new 为 全局operator new ,因为它是一个文件中的函数。
1. 于是我们就可以对 operator new 进行重载了:
2. 重载之后,我们可以在其中自己进行内存分配。(比如说,不使用 malloc进行实现)
但是重载 operator 必须非常的注意!
文章说的非常好, 有非常多的注意事项! 有好处也有坏处,
陈硕的文章 说的也非常好! 值得一看,看不懂别怪我。
这里的升级版本是: 可以在类中重载 operator new 和 placement new。 这个需要在 google 上搜索一下。
new 的用法!
当我们自己重载了 new 之后,就可以进行内存管理了,必须说构造一个内存池! 当然,这是下一篇文章的内容了。
(文章还会在不断的修改的)