<<Effective C++>>读书笔记8: 定制new和delete

每一个Item都很经典,都需要去思考揣摩,我在这里将要点抽象出来,便于日后快速回忆;我只是在做文章的“搬运工”。

        Item 49 了解 new-handler 的行为
1. 声明的结尾处的 "throw()" 是一个异常规范,它是说这个函数不会抛出任何异常。
2. 当 Widget 从 NewHandlerSupport<Widget> 继承时,它其实是在说:我是 Widget,而我要从针对 Widget 的 NewHandlerSupport类 继承。
3. 在表达式 "new (std::nothrow) Widget" 中(不抛异常的new),发生了两件事:首先,operator new 的 nothrow 版本被调用来为Widget object 分配足够的内存,如果分配失败,operator new 返回null pointer。如果它成功了,Widget构造函数被调用。而在此刻,危机可能会出现:Widget构造函数可能new 出来一些内存,而如果它并没有被强迫使用 nothrow new。那么,虽然在 "new (std::nothrow) Widget" 中调用的 operator new 不会抛出,Widget构造函数却可以。如果它这样做了,exception 像往常一样被传播。结果?使用 nothrow new 只能保证 operator new 不会抛出,不能保证"new (std::nothrow) Widget"绝不会导致一个 exception。在所有的可能性中,你最好不要使用nothrow new。
   [这个再次说明了异常在构造函数中的重要性]
   [我在工作用基本还是用的nothrow方式,如果内存分配失败,返回NULL, 加上FAILED日志也是比较容易定位问题的]
4. 当 operator new 不能满足一个内存请求时,它反复调用 new-handler function 直到它能找到足够的内存。
   [在new-handler中间可以做一些内存优化,释放一些内存,从而下次operator new时可以分配到内存]
   [工作中基本上没有用过set_new_handler,但我依旧觉得这是一种不错的机制,在内存分配失败之后可以做一些有效的补救措施;new-handler和异常处理结合使用,可以产生双剑合璧的威力]
   [参考对 set_new_handler的总结。]
  
        Item 50: 了解替换 new 和 delete 合理时机
1. 在对于客户可用的内存的之前和之后,自定义 operator news 可以跨越分配块,在这些空间(始端和末端)放置已知的字节模式 (打标记)。operator deletes 会去检查这些 “标记”是否依旧保持原样。如果不是,在这个分配块的生存期间的某个时刻发生了一个上溢或者下溢,而且 operator deletes 可以记录这件事以及那个指针的值。
   [一种内存管理的好方法,稍微有点麻烦]
2. 数据上溢(data overruns):在一个已分配块的末端之后写入;下溢(underruns):在一个已分配块的始端之前写入。
3. 一种架构可能要求指针要出现在四的倍数的地址上(也就是说,按照四字节对齐)或者 doubles(双精度浮点型)必须出现在八的倍数的地址上(八字节对齐)。不遵守这样的约束会导致运行时硬件异常。其它的架构可能会宽容一些,但是如果满足了排列对齐的次序会得到更好的性能。
   [4字节对齐,这个在嵌入式编程中尤其重要]
4. alignment(字节对齐)这样的细节可以用于区分专业品质的内存管理器和那些由需要解决其它任务而心烦意乱的程序员匆匆拼凑出来的东西。编写一个几乎能工作的自定义内存管理器相当容易。编写一个工作得很好的要困难得多。
   
        Item 51  编写 new 和 delete 时要遵守惯例
1. C++ 即使要求请求零字节,operator new 会将0字节请求当作1个字节来处理,这样会简单,合法,有效。
2. new-handling function(set_new_handler) 做了以下事情之一:使得更多的内存可用,安装一个不同的 new-handler,卸载 new-handler,抛出一个 bad_alloc 或从 bad_alloc 派生的 exception,或不再返回。
3. 编写一个自定义的内存管理器的最常见的原因之一是为了优化某个特定 class 的对象的分配,而不是某个 class 或它的任何派生类的。也就是说,给定一个 class X 的 operator new,这个函数的行为通常是为大小为 sizeof(X) 的对象设计的——绝不会更大或者更小。
4. 动态分配数组可能包括额外的空间用于存储数组元素的数量。
5. 如果你在基类中遗漏了 virtual析构函数,operator delete可能无法正确工作。
   [后续编写一个自定义的new和delete]

        Item 52 如果编写了 placement new,就要编写 placement delete
1. runtime system(运行时系统)恰当地调用operator new 的版本相对应的 operator delete,但是只有在它知道哪一个 operator delete——可能有许多——最恰 当的时候它才能做到这一点。如果你正在摆弄具有常规的 signatures(识别特征)的 new 和 delete 版本,这不成问题,因为常规的 operator new对应常规的 operator delete。
2. 当一个 operator new函数持有额外的参数(除了那个必要的 size_t 参数),这个 function 就被称为 new 的 placement 版本。 
   [我原以为只有标准库的placement new才是placement new]
3. 有一个特别有用的 placement new,它持有一个指针,这个指针指定了一个 object 被构造的位置。那个 operator new 如下:
   void* operator new(std::size_t, void *pMemory) throw();   // "placement
   new 的这个版本是 C++ 标准库的一部分,只要 #include <new> 你就可以访问它。
4. "placement new" 意味着持有额外参数的 new 的任意版本。
5. 只有在调用一个与 placement new 相关联的 constructor(构造函数)时发生一个 exception(异常),placement delete 才会被调用。将 delete 施加于一个指针(诸如上面的 pw)绝对不会引起一个 delete 的 placement 版本的调用。绝对不会。
   这就意味着为了预防所有与 new 的 placement 版本相关的内存泄漏,你必须既提供常规 operator delete(用于构造过程中没有抛出 exception时),又要提供一个持有与 operator new 相同的额外参数的 placement 版本。

   [这一小节的内容比较生僻,也是比较容易出错的,切记切记]


   [这一章是我看的比较久的,说明我对new和delete理解的还比较薄弱]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值