读书笔记:Effective C++ 炒冷饭 - Item52 写了placement new也要写placement delete

读书笔记:Effective C++ 炒冷饭 - Item52 写了placement new也要写placement delete
[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-06-15

在item16和17里大师曾经介绍过,一个new的过程大致分两步:
   - 申请内存
   - 调用构造函数构造新对象

如果第一步成功而第二步失败,一个成熟的系统应该能回撤第一步,释放刚分配的内存空间。
如果第一步用的是普通的new函数,C++是能够找到与之匹配的delete函数的。
// normal form of new operator
void *   operator   new (std::size_t)  throw (std::bad_alloc);
// is matched with the global one
void   operator  delete( void   * rawMemory)  throw ();
// or the class-scope one
void   operator  delete( void *  rawMemory, std::size_t size)  throw ();

而如果用的是非常规的new函数,情况就不一样了。这里说的“非常规new”,指的是placement new。
这里说的placement new指的是除去size_t参数外,还包含了其他的参数的new函数。
   最原始的placement new版本在C++的new库中:
void *   operator   new (std::size_t,  void   * pMemory)  throw ();

   比较常见的用途是申请一大批内存放在某个vector中,到需要分配内存的时候用该placement new指定在某个地址开始申请内存。

在调用placement new的过程中,一旦第二步出错,系统依照惯例会用一个delete来释放内存,不过因为这次new的方式不同寻常,也就需要一个不同寻常的delete来释放。
系统需要的是一个参数类型、个数都一致的delete,placement delete来释放由那个placement new鼓捣出来的内存空间。
如果找不到……对不起,内存泄漏。

但是有一点需要注意的是:如果使用了placement new,除了要写好与之对应的placement delete外,还要再写一个“常规”的delete函数。
因为对于delete而言,placement delete是在当placement new遇见失败异常时释放新近分配的内存用的;“常规”的delete则是用于正常途径的delete。如下的语句,是不会调用placement delete的。
delete aObject;

最后要提的一点是:注意不同名字域中的名字覆盖/隐藏。
如果在某个类中只声明了一个placement new,那么用户就无法使用全局范围的默认new函数;如果子类中只声明了一个placement new,那么父类的另外形式的new函数就会被隐藏。如何做到透明的使用所有可能的new/delete?
直接粘贴大师的代码吧,一来是这个已经很直接没有必要再另做消化,二来我感冒了……

class  StandardNewDeleteForms {
public :
  
//  normal new/delete
   static   void *   operator   new (std::size_t size)  throw (std::bad_alloc)
  { 
return  :: operator   new (size); }
  
static   void   operator  delete( void   * pMemory)  throw ()
  { ::
operator  delete(pMemory); }

  
//  placement new/delete
   static   void *   operator   new (std::size_t size,  void   * ptr)  throw ()
  { 
return  :: operator   new (size, ptr); }
  
static   void   operator  delete( void   * pMemory,  void   * ptr)  throw ()
  { 
return  :: operator  delete(pMemory, ptr); }

  
//  nothrow new/delete
   static   void *   operator   new (std::size_t size,  const  std::nothrow_t &  nt)  throw ()
  { 
return  :: operator   new (size, nt); }
  
static   void   operator  delete( void   * pMemory,  const  std::nothrow_t & throw ()
  { ::
operator  delete(pMemory); }
};

class  Widget:  public  StandardNewDeleteForms {            //  inherit std forms
public :
   
using  StandardNewDeleteForms:: operator   new ;           //  make those
    using  StandardNewDeleteForms:: operator  delete;        //  forms visible

   
static   void *   operator   new (std::size_t size,           //  add a custom
                             std::ostream &  logStream)    //  placement new
      throw (std::bad_alloc);

   
static   void   operator  delete( void   * pMemory,            //  add the corres-
                               std::ostream &  logStream)  //  ponding place-
     throw ();                                             //  ment delete
  
// ..
};

你可能感兴趣的:(读书笔记:Effective C++ 炒冷饭 - Item52 写了placement new也要写placement delete)