placement delete

来源:互联网 发布:淘宝输入nick不合法 编辑:程序博客网 时间:2024/06/05 19:40

一个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

  //..

};