/*条款52:写了placement new 也要写Placement delete*/
#include<iostream>
using namespace std;
//class Widget {};
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
// placement new :如果在operator接受的参数除了一定会有的那个size_t之外还有其他,这个便是所谓的placement new
//一个比较常用的 placement new 接受一个指针指向对象该被构造之处如下:
// void*operator new(std::size_t ,void*pMemory)throw(); 这个版本的new已被纳入C++标准程序库,头文件#include<new>,它的用途之一是负责在vector的未使用空间上创建对象,实际上它正是这个函数的命名根据:一个特定位置的new,上下文语境往往也能够使意义不明确的含糊话语清晰起来
//如果没有与上面对象的operator delete 就无法对内存分配动作做恢复所以要加上下面的内容
static void operator delete (void*pMemory)throw();//如果没有发生异常,则调用对应的delete
static void operator delete(void*pMemory, std::ostream&logStream)throw();
};//但这里有一个名字掩盖的问题 调用时要传递对应的参数,第二是子类可能有名字相同的函数把基类new掩盖掉
/////---------------------上述出现 的掩盖的问题可以像如下方式去解决
class StandardNewDeleteForms {
public:
//正常的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 ::new_handler(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);
}
};
//凡是想以自定形式扩充标准形式的客户,可利用继承机制及using 声明式取得标准形式
class Widget :public StandardNewDeleteForms {
public:
using StandardNewDeleteForms::operator new;//继承标准形式,让这些形式可见
using StandardNewDeleteForms::operator delete;
static void*operator new(std::size_t size, std::ostream&logStream)throw(std::bad_alloc);
static void operator delete(void*pMemory, std::ostream&logSteam)throw();//添加一个自定的placement delete
//..
};
int main() {
Widget*pw = new Widget;//这个表达式调用了两个函数,1 operator new 2 Widget的default构造函数
//假设第一个调用成功,第二个函数却抛出异常,那么步骤一的内存分配所得必须取消并恢复旧观,否则就是内存漏洞,并且客户手上没有指针指向被归还的内存,取消步骤一就落到了C++运行期系统身上了
Widget *pw1 = new (std::cerr)Widget;//调用operator new 并传递cerr为ostream实参,这个动作会在Widget构造函数抛出异常时泄漏内存
// 这里的问题是如果内存分配成功,而Widget构造函数抛出异常,运行期系统有责任取消opeator new 的分配并恢复旧观,然而运行期系统无法知道真正被调用的那个operator new 如何动作,因此无法取消分配并恢复旧观,那么我们可以根据上面的new找出对应的operator delete
// void operaotr(void*,std::ostream&)throw();
system("pause");
return 0;
}
条款52:写了placement new 也要写Placement delete
最新推荐文章于 2025-01-03 16:17:50 发布