条款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的妙妙屋!
