[笔记]《Effective C++》第八章Customizing new and delete


条款49:Understand the behavior of the new-handler.

  • 当operator new无法满足某一内存分配需求时,它会抛出异常。当operator new抛出异常以反映一个未获满足的内存需求之前,它会先调用一个客户指定错误处理函数,一个所谓的new-handler
  • 为了指定这个“用以处理内存不足”的函数,客户必须调用set_new_handler,那是声明于的一个标准程序库函数
namespace std{
  typedef void(*new_handler)( );
  new_handler set_new_handler(new_handler p) throw();
}
  • new_handler是个typedef,定义出一个指针指向函数,该函数没有参数也不返回任何东西。set_new_handler则是“获得一个new_handler并返回一个new_handler”的函数
  • 一个设计良好的new-handler函数必须做以下事情:
    • 让更多内存可被使用。
    • 安装另一个new-handler。
    • 卸除new-handler,也就是将null指针传给set_new_handler。
    • 抛出bad_alloc (或派生自bad_alloc)的异常。
    • 不返回,通常调用abort或exit。

条款50:Understand when it makes sense to replace new and delete.

替换编译器提供的operator new或operator delete的理由:
最常见的三个:

  • 用来检测运用上的错误。各式各样的编程错误可能导致数据 "overruns"(写入点在分配区块尾端之后)或 "underruns"(写入点在分配区块起点之前)。如果我们自行定义一个 operator news,便可超额分配内存,以额外空间(位于客户所得区块之前或后)放置特定的byte patterns(即签名,signatures)。
  • 为了强化效能。如果你对你的程序的动态内存运用型态有深刻的了解,通常可以发现,定制版之 operator new和operator delete性能胜过缺省版本。
  • 为了收集使用上的统计数据。

其他理由:

  • 为了增加分配和归还的速度。
  • 为了降低缺省内存管理器带来的空间额外开销。
  • 为了弥补缺省分配器中的非最佳齐位(suboptimal alignment)。
  • 为了将相关对象成簇集中。
  • 为了获得非传统的行为。

条款51:Adhere to convention when writing new and delete.

  • 实现一致性operator new必得返回正确的值,内存不足时必得调用new-handling函数(见条款49),必须有对付零内存需求的准备,还需避免不慎掩盖正常形式的new
    • C++规定,即使客户要求0 bytes,operator new也得返回一个合法指针
  • operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用new-handler以做到:让更多内存可用、安装另一个new-handler、卸除new-handler、抛出bad_alloc异常(或其派生物),或是承认失败而直接return。
  • 如果你决定写个operator new[],记住,唯一需要做的一件事就是分配一块未加工内存(raw memory)
  • C++保证“删除null指针永远安全”。operator delete应该在收到null指针时不做任何事

条款52:Write placement delete if you write placement new.

  • 当你写一个placement operator new,请确定也写出了对应的placementoperator delete。如果没有这样做,你的程序可能会发生隐微而时断时续的内存泄漏
    • 如果operator new接受的参数除了一定会有的那个size_t之外还有其他,这便是个所谓的placement new。下面的operator new就是个placement版本。
      class Widget{
      public:
        ...
        static void* operator new(std::size_t size, std::ostream& logStream)
          throw(std::bad_alloc);  //非正常形式的new
        static void operator delete(void* pMemory std::size_t size)
          throw();                //正常的class专属delete
        ...
      };
      
    • 如果一个带额外参数的operator new没有“带相同额外参数”的对应版operator delete,那么当new的内存分配动作需要取消并恢复旧观时没有任何operator delete会被调用
    • placement delete只有在“伴随placement new调用而触发的构造函数”出现异常时才会被调用。对着一个指针施行delete绝不会导致调用placement delete
  • 由于成员函数的名称会掩盖其外围作用域中的相同名称,你必须小心避免让class专属的news掩盖客户期望的其他news(包括正常版本)。