您的位置:首页 > 其它

定制new和delete

2012-12-20 13:55 423 查看
Item 49 Understand the behavior of the new-handler.了解new-handler的行为。

当operator new抛出异常之前以反映一个未满足的内存需求之前,会先调用称为new-handler的客户指定的错误处理函数。

new_handler是一个typedef的函数指针:typedef void ( *new_handler )( );

定制模板基类来定制operator new和set_new_handler函数的办法如下:

class NewHandlerHolder
{
public:
explicit NewHandlerHolder(new_handler nh):handler(nh) {}
~NewHandlerHolder() {set_new_handler(handler);}
private:
new_handler handler;
};

template <typename T>
class NewHandlerSupport
{
public:
static new_handler set_new_handler(new_handler p) throw();
static void* operator new(size_t size) throw(bad_alloc);
private:
static new_handler currentHandler;
};

template <typename T>
new_handler NewHandlerSupport<T>::currentHandler=NULL;

template <typename T>
new_handler NewHandlerSupport<T>::set_new_handler(new_handler p) throw()
{
new_handler oldHandler=currentHandler;
currentHandler=p;
return oldHandler;
}

template <typename T>
void* NewHandlerSupport<T>::operator new(size_t size) throw(bad_alloc)
{
NewHandlerHolder h(set_new_handler(currentHandler));
return ::operator new(size);
}

class Widget:public NewHandlerSupport<Widget>
{
public:
Widget() {cout<<"Widget::Widget()"<<endl;}
~Widget() {cout<<"Widget::~Widget()"<<endl;}
};

void OutOfMemory()
{
cerr<<"Unable to satisfy request for memory."<<endl;
abort();
}

int _tmain(int argc, _TCHAR* argv[])
{
Widget::set_new_handler(OutOfMemory);
Widget *pw=new Widget();
delete pw;
return 0;
}


其中采用了用对象管理资源的手法。template机制为会每一个T生成一份currentHandler。

注意的一件事情:operator new不止一次尝试分配内存,并在每次失败后调用new-handling函数,只有当new-handling函数的指针是null,operator new才会抛出异常。

new-handler一般做以下几件事情:让更多内存可用,安装另一个new-handler,卸除new-handler,抛出bad_alloc异常,或是承认失败而直接return。

Item 50 Understand when it makes sense to repace new and delete.了解new和delete的合理替换时机。

一般有如下理由:

(1)用来检测运用上的错误。

(2)为了强化效能。

(3)为了收集使用上的统计数据。

(4)为了降低缺省内存管理其带来的空间额外开销。

(5)为了弥补缺省分配器中的非最佳齐位。

(6)为了将相关对象成簇集中。placement new。

(7)为了获得非传统的行为。

但无论有何种理由,请确认的确想替换掉编译器提供的operator new。

Item 51 Adhere to convention when writing new and delete.编写new和delete时需固守常规。

operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用new-handler。

operator new应该有能力处理0byte申请。class专属版本则应该处理“比正确大小更大的(错误)申请”。
//不太明白的地方。

operator delete应该在收到null指针时不做任何事。class专属版本则还应该处理“比正确大小更大的(错误)申请”。

Item 52 Write placement delete if you write placement new.写了placement new也要写placement delete。

class StandardNewDeleteForms
{
public:
static void* operator new(size_t size) throw(bad_alloc)
{
return ::operator new(size);
}

static void operator delete(void* pMemory) throw()
{
cout<<"standard delete(void* pMemory)"<<endl;
::operator delete(pMemory);
}

static void* operator new(size_t size,void* ptr) throw()
{
return ::operator new(size,ptr);
}

static void operator delete(void* pMemory,void* ptr) throw()
{
cout<<"standard delete(size_t size,void* ptr)"<<endl;

::operator delete(pMemory,ptr);
}

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

static void operator delete(void *pMemory,const nothrow_t&) throw()
{
cout<<"standard delete(void *pMemory,const nothrow_t&)"<<endl;

::operator delete(pMemory);
}
};

class Widget : public StandardNewDeleteForms
{
public:
using StandardNewDeleteForms::operator new;
using StandardNewDeleteForms::operator delete;

static void* operator new(size_t size,ostream& os) throw(bad_alloc)
{
os<<"my operator new"<<endl;
return operator new(size);
}

static void operator delete(void* rawMemory,ostream& os) throw()
{
os<<"my operator delete"<<endl;
operator delete(rawMemory);
}
};

int _tmain(int argc, _TCHAR* argv[])
{
Widget *w=new (cerr)Widget;

delete w;
return 0;
}


Widget *w=new (cerr)Widget;

这样的一句代码,引起的是在Widget类内定义的static void* operator new(size_t size,ostream& os) throw(bad_alloc)的调用来分配内存,继而调用构造函数,完成对象的构造。

但是在调用构造函数的过程中,如果发生异常,则会调用static void operator delete(void* rawMemory,ostream& os) throw()来收回已分配的内存,并恢复旧观。

如果没发生异常,也就是一个对象正常构造完毕,则在delete w;调用的时候,调用的则是在StandardNewDeleteForms中定义的static void operator delete(void* pMemory) throw()来完成对象的析构和内存的回收工作。

因此在自定义一个专属版本的placement new的时候,一定要自定义一个带有相同额外参数的placement delete来处理出现异常情况的内存回收。

为了防止在一个类中自定义的placement new遮掩正常的operator new版本,可以采取将正常版本的operator new和operator new定义在基类的办法,由自定义placement new和placement delete的类来继承。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: