Effective C++——条款52(第8章)

来源:互联网 发布:logback 不打印sql 编辑:程序博客网 时间:2024/06/07 05:40

条款52: 写了placement new 也要写placement delete

Write placement delete if you write placement new

    placement new 和 placement delete 并非在C++常见.回忆条款16和条款17,当写一个如下所示的 new 表达式:
Widget* pw = new Widget;
    共有两个函数被调用:一个用以分配内存的 operator new,一个Widget的 default 构造函数.
    假设其中第一个函数调用成功,第二个函数却抛出异常.既然那样,步骤一的内存分配所得必须取消并恢复旧观,否则会造成内存泄露(memory leak).在这个时候,客户并没有能力归还内存,因为如果Widget构造函数抛出异常,pw尚未被赋值,客户手上也没有指针指向该被归还的内存.取消步骤一并恢复旧观的责任因此落到C++运行期系统身上.
    运行期系统会调用步骤一所调用的 operator new 的相应 operator delete 版本,前提当然是它必须知道哪一个(因为可能有许多个)operator delete 该被调用.如果目前面对的是拥有正常签名式(signature)的 new 和 delete,这并不是问题,因为正常的 operator new:
void* operator new(std::size_t) throw(std::bad_alloc);
    对应于正常的 operator delete:
void operator delete(void* rawMemory) throw();// global作用域中的正常签名式void operator delete(void* rawMemory, std::size_t size) thow();// class作用域中典型的签名式
    因此,当只使用正常形式的 new 和 delete,运行期系统毫无问题可以找出那个"知道如何取消new所作所为并恢复旧观"的 delete .然而当开始声明非正常形式的 operator new,也就是带有附加参数的 operator new,"究竟哪一个delete伴随这个new"的问题便浮现了.
    如果 operator new 接受的参数除了一定会有的那个 size_t 之外还有其他,这便是所谓的placement new .因此,上述的 operator new 是个placement版本.众多placement new 版本中特别有用的一个是"接受一个指针指向对象该被构造的地方",那样的 operator new 类似这样:
void* operator new(std::size_t, void* pMemory) throw(); // placement new
    这个版本的 new 已被纳入C++标准程序库,只要#include <new>就可以取用它.这个 new 的用途之一是负责在vector的未使用空间上创建对象.实际上它正是这个函数的命名根据:一个特定位置上的 new .
    类似于 new 的placement版本,operator delete 如果接受额外参数,便称为placement delete .
    注意:
    当写一个placement operator new,请确定也写出相应的placement operator delete .如果没有那样做,程序可能会发生隐微而时断时续的内存泄露.
    当声明placement new 和placement delete,请确定不要无意识(非故意)地遮掩了它们的正常版本.

0 0
原创粉丝点击