placement delete只有在伴随着“placement new调用而触发的构造函数”出现故障时才会被调用。
当placement new调用发生故障时,编译器会在系统中国调用与placement new参数个数与参数类型一致的placement delete去恢复内存区避免内存泄漏。
当使用placement new operator构建类对象时,对相应的指针实行delete operator是不会调用placement delete operator。这就意味着如果要解决所有与placement new相关的内存泄漏问题,我们就必须提供一个正常的operator delete版本(用于在正常构造对象时析构对象)和一个placement delete operator(由于在使用placement 类型构造对象异常时还原内存)。
附带一提,由于成员函数的名称会遮掩其外围作用域中的相同名称,你必须小心避免让类专属版本的new遮掩客户期望的其他new(包括正常版本)。
// ConsoleApplication31.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<string>
using namespace std;
#include <iostream>
using namespace std;
class B{
public:
B(){ cout << "ctor B" << endl; }
~B(){ cout << "dtor B" << endl; }
void * operator new(size_t size, ostream& out){
out << "new B" << endl;
return ::operator new(size);
}
//placement delete只有在“伴随placement new调用而触发的构造函数”出现异常才会被调用。
//对着一个指针(例如上述的pw)施行delete绝不会导致调用placement delete,绝对不会!!!
// 这意味如果要对所有与placement new相关的内存泄露宣战,
//我们必须同时提供一个正常的placement delete(用于构造期间无任何异常被抛出)
//和一个placement 版本(用于构造期间有异常被抛出)。后者的额外参数必须和operator new一样。
// 附带一提,由于成员函数的名称会遮掩其外围作用域中的相同名称,
//你必须小心避免让类专属版本的new遮掩客户期望的其他new(包括正常版本)
void operator delete(void *mem, ostream& out){
out << "delete B" << endl;
::operator delete(mem);
}//只有在重载operator new调用失败的情况下,编译器才会匹配该operator delete函数。
};
int _tmain(int argc, _TCHAR* argv[])
{
B* pb1 = ::new B;//调用全局作用域签名
B* pb2 = new (cout)B;
::delete pb1;
//delete pb2;异常,调用自定义placement delete操作(覆盖全局正常版本delete operator)
pb2->~B();//显示析构
B::operator delete (pb2,cout);//显示<span style="font-family: Arial, Helvetica, sans-serif;">调用自定义placement delete操作</span>
system("pause");
return 0;
}