条款8:了解各种不同意义的 new 和 delete
1️⃣ 问题的引入
- 如何理解
new operator
和opertor new
之间的差异 ? - 什么是
placement new
,它的作用是什么?
2️⃣ 案例解析
1 | string* ps = new string("Memory Management"); |
- 这里使用的
new
是所谓的new operator
。这个操作符是由语言内建的,不能被改变意义。 - 它的动作以下两方面:
- 第一,它分配足够的内存,用来放置某类型的对象。
- 第二,它调用一个
constructor
,为刚才分配的内存中的那个对象设定初值。
- 我们能够改变的是用来容纳对象的那块内存的分配行为。
newo perator
调用某个函数,执行必要的内存分配,我们可以重写那个函数,改变其行为。- 这个函数的名称叫做
operator new
。
3️⃣ 进一步理解
- 函数
operator new
的定义式:
1 | void* operator new(size_t size); |
- 返回值和参数解析
* 返回值类型为 `void*`,返回的指针,指向一块原始的、未设初值的内存
* `size_t` 表示需要分配多少内存。
* `operator` 可以被重载,加上额外的参数,但是第一参数必须是`size_t`。
- 作用
* `operator new`和`malloc`一样。它唯一任务就是分配内存。它不知道什么是`constructr`, `operator new`只负责内存分配。
new operator
的流程
1 | void *memory = //取得原始内存(rawmemory)。 |
4️⃣ Placement new
- 应用场景:你已拥有一些分配好的原始内存,只需要在上面构建对象。
1 | class Widget { |
- 解析
- 函数返回指针,指向一个
Widgetobject
,它被构造于传递给此函数的一块内存缓冲区。 new (buffer) Widget (widgetSize);
- 指定一个额外自变量(
buffer
)作为new operator
隐式调用operator new
时所用。 - 被调用的
operator new
除了接受一定得有的size_t
自变量之外,还接受了一个void*
参数,指向一块内存,准备用来接受构造好的对象。
- 指定一个额外自变量(
- 函数返回指针,指向一个
- 作用
operator new
的目的是要为对象找到一块内存,然后返回一个指针指向它。- 在
placement new
的情况下,调用者已经知道指向内存的指针了,因为调用者知道对象应该放在哪里。因此placement new
唯一需要做的就是将它获得的指针再返回。
5️⃣ 三类new的使用场景
- 如果你只是打算分配内存,请调用
operator new
,那就没有任何constructor
会被调用。 - 如果你打算在
heap objects
产生时自己决定内存分配方式,请写一个自己的operator new
,并使用new operator
,它将会自动调用你所写的operator new
。 - 如果你打算在已分配(并拥有指针)的内存中构造对象,请使用
placement new
。
6️⃣ 删除(Deletion)与内存释放(Deallocation)
问题的引入
- 为了避免
resourceleaks
(资源泄漏),每一个动态分配行为都必须匹配一个相应但相反的释放动作 operator delete
对于内建的delete operator
,等价operator new
对于new operator
一样
- 为了避免
案例引入
1
2
3string* ps;
...
delete ps;delete
的执行流程- 先调用
ps->~string()
,先调用对象的析构函数。 - 再调用
operator delete(ps)
,再释放对象所占用的内存。
- 先调用
进一步理解
- 如果使用
placement new
,在某内存块中产生对象,就避免对那块内存使用delete operator
。 - 因为
delete operator
会调用operator delete
来释放内存,但是该内存内含的对象最初并非是由operator new
分配得来的。 - 毕竟
placement new
只是返回它所接收的指针而已,谁知道那个指针从哪里来呢?所以为了抵消该对象的constructor
的影响,你应该直接调用该对象的destructor
。
- 如果使用
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 GYu的妙妙屋!