在 C++ 中,动态创建一个新的对象所采用的常规语法是 Object* obj = new Object();
这种形式。这种形式的 new 表达式 在编译器生成代码时会执行两个操作:
- 调用 operator new 函数分配原始内存(功能如 malloc);
- 调用 Object 类的构造函数 Object::Object()。
如下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
将有类似下面的输出:
Object() with n=626
Object @ 00DAEF60 with n=626
~Object() with n=626
于是,这种形式的 new 有一个明显的缺陷:无法手动管理内存的分配,重载 operator new 可是强烈不建议的。
由于构造函数无法手动调用,如果我们需要手动管理 new 时的内存分配,应该怎么办呢?
这就会用到一种所谓的 placement new 语法:new (placement) Object();。
这种形式的语法可不常见。其中括号内的 placement 即是我们手动指定的内存地址。 这种形式的 new 不会自动申请内存,而是直接使用我们提供的(不管值是多少,NULL 也是可以的),所以我们需要保证内存有效,并且大小合适(不能小于对象的字节数)。 然后在该内存上调用对象的构造函数来构造对象。由于内存是我们提供的,我们将不能直接 delete 掉该对象。而是 手动调用析构函数,然后手动回收内存(如果有必要)。
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
将有类似下面的输出,注意它们的地址全部是一样的:
mem: 008FFA08
---------------------------------------
Object() with n=220
obj: 008FFA08
Object @ 008FFA08 with n=220
~Object() with n=220
---------------------------------------
Object() with n=626
Object @ 008FFA08 with n=626
~Object() with n=626
---------------------------------------
Object() with n=123
Object @ 02D95B28 with n=123
~Object() with n=123
例子也举了几个了,话说 placement new 用在什么场合?
一言以蔽之:需要手动管理内存的地方!。比如:
- 对象内存池,要知道,频繁分配小内存是会导致内存碎片严重,而且分配效率非常低下;
- 标准库,标准库就大量运用了内存池,不过它有另外一个名字:Allocator。