• 条款八: 写operator new和operator delete时要遵循常规


    自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数(见条款7)处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new,不过这是条款9的话题。

    有关返回值的部分很简单。如果内存分配请求成功,就返回指向内存的指针;如果失败,则遵循条款7的规定抛出一个std::bad_alloc类型的异常。operator new实际上会不只一次地尝试着去分配内存,它要在每次失败后调用出错处理函数,还期望出错处理函数能想办法释放别处的内存。只有在指向出错处理函数的指针为空的情况下,operator new才抛出异常。

    c++标准要求,即使在请求分配0字节内存时,operator new也要返回一个合法指针。

    非类成员形式的operator new的伪代码看起来会象下面这样:

    void * operator new(size_t size)        // operator new还可能有其它参数
    {                                      
    
      if (size == 0) {                      // 处理0字节请求时,
        size = 1;                           // 把它当作1个字节请求来处理
      }                                     
      while (1) {
        分配size字节内存;
    
        if (分配成功)
          return (指向内存的指针);
    
        // 分配不成功,找出当前出错处理函数
        new_handler globalhandler = set_new_handler(0);
        set_new_handler(globalhandler);
    
        if (globalhandler) (*globalhandler)();
        else throw std::bad_alloc();
      }
    }

    处理零字节请求的技巧在于把它作为请求一个字节来处理。

    operator new经常会被子类继承,这会导致某些复杂性。大多数针对类所写的operator new(包括条款10中的那种)都是只为特定的类设计的,不是为所有的类,也不是为它所有的子类设计的。这意味着,对于一个类x的operator new来说,函数内部的行为在涉及到对象的大小时,都是精确的sizeof(x):不会大也不会小。但由于存在继承,基类中的operator new可能会被调用去为一个子类对象分配内存:

    class base {
    public:
      static void * operator new(size_t size);
      ...
    };
    
    class derived: public base       // derived类没有声明operator new
    { ... };                         // 
    
    derived *p = new derived;        // 调用base::operator new

    如果base类的operator new不想费功夫专门去处理这种情况——这种情况出现的可能性不大——那最简单的办法是把这个“错误”数量的内存分配请求转给标准operator new来处理,象下面这样:

    void * base::operator new(size_t size)
    {
      if (size != sizeof(base))             // 如果数量“错误”,让标准operator new
        return ::operator new(size);        // 去处理这个请求
                                            //
    
      ...                                   // 否则处理这个请求
    }

    如果想控制基于类的数组的内存分配,必须实现operator new的数组形式——operator new[]

    重写operator new(和operator new[])时所有要遵循的常规就这些。对于operator delete(以及它的伙伴operator delete[]),情况更简单。所要记住的只是,c++保证删除空指针永远是安全的,所以你要充分地应用这一保证。下面是非类成员形式的operator delete的伪代码:

    void operator delete(void *rawmemory)
    {
      if (rawmemory == 0) return;    //如果指针为空,返回
                                     // 
    
      释放rawmemory指向的内存;
    
      return;
    }

    假设类的operator new将“错误”大小的分配请求转给::operator new,那么也必须将“错误”大小的删除请求转给::operator delete:

    class base {                       // 和前面一样,只是这里声明了
    public:                            // operator delete
      static void * operator new(size_t size);
      static void operator delete(void *rawmemory, size_t size);
      ...
    };
    
    void base::operator delete(void *rawmemory, size_t size)
    {
      if (rawmemory == 0) return;      // 检查空指针
    
      if (size != sizeof(base)) {      // 如果size"错误",
        ::operator delete(rawmemory);  // 让标准operator来处理请求
        return;                        
      }
    
      释放指向rawmemory的内存;
    
      return;
    }
  • 相关阅读:
    request:fail parameter error: parameter.url should be String instead of Undefined;
    高性能Mysql笔记 — 索引
    机器学习 — 构建价格模型
    机器学习 — 决策树建模
    机器学习 — 文档过滤
    机器学习 — 优化
    机器学习 — 搜索及排名
    机器学习 — 发现群组
    机器学习 — 提供推荐
    docker
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3894619.html
Copyright © 2020-2023  润新知