Effective C++条款49:了解new-handler的行为

当operator new 无法满足某一内存分配需求时,它会抛出异常,以前它会返回null指针.
当operator new 抛出异常反映一个未获满足的内存需求之前,它会先调用一个客户指定的错误处理函数,一个所谓的new-handler。

namespace std
{
	typedef void(*new_handler)();
	new_handler set_new_handler(new_handler p) throw();//注意C++11应该是使用noexcept 表明不会抛出异常
}

set_new_handler的参数是个指针,指向operatornew无法分配足够内存时该调用的函数,其返回值也是个指针,指向set_new_handler被调用前正在执行的那个new_handler函数.

可以这样使用set_new_handler:

void outOfMem()
{
	std::cerr << "Unable to satisfy request for memory\n";
	std::abort();
}
int main()
{
	std::set_new_handler(outOfMem);
	int * p = new int[10000000000];
	...
}

设计一个良好的new-handler函数必须做以下事情:
1.让更多内存可被使用,这样可以让operatornew内的下一次分配动作可能成功,实现这个策略的一个做法是:程序一开始就分配一大块内存,当newhandler第一次被调用,将它们释还给程序使用
2.安装另一个new-handler,如果目前这个handler无法取得更多可用内存,或许它知道另外哪个handler有此能力.果真如此,目前这个newhandler就可以安装另外那个newhandler以替换自己.下次当operator new 调用new-handler调用的是最新安装的那个
3.卸除new-handler:也就是将null指针传给set_new_handler.一旦没有安装任何new-handler,operator new会在内存分配不成功时抛出异常.
4.抛出bad_alloc的异常
5.不返回,通常调用abort或exit

有时候,或许你希望以不同的方式处理内存分配失败情况,你希望视被分配物属于哪个class而定,但C++并不支持类专属new-handler,但你可以自己实现出这种行为,只需令每一个class提供自己的set_new_handleroperator new即可.
其中set_new_handler使客户得以指定类专属的new-handler,operator new则确保在分配class对象内存的过程中以类专属的new-handler替换全局new handler.

假设你打算处理widget class的内存分配失败情况.首先你必须登录当operator new无法为一个widget对象分配足够内存时调用的函数,看起来像这样:

class widget
{
public:
	static std::new_handler set_new_handler(std::new_handler p) noexcept;
	static void* operator new(std::size_t size)thorw(std::bad_alloc);
	private:
		static std::new_handler currentHandler;
};
std::new_handler widget::currentHandler = 0;

widget内的set_new_handler函数会将它获得的指针存储起来,然后返回先前存储的指针:

std::new_handler Widget::set_new_handler(std::new_handler p) noexcept
{
	std::new_handler oldHandler = currentHandler;
	currentHandler = p;
	return oldHandler;
}

widget的operator new 做以下事情:
1.调用标准的set_new_handler,告知widget的错误处理函数.这会将Widget的new_handler安装为global new-handler
2.调用global operator new,执行内存分配,如果分配失败,global operator new 会调用widget的new-handler,因为那个函数才刚被安装为global new-handler…如果global operator new最终无法分配内存,抛出bad_alloc异常.
3.如果global operator new能够分配足够一个wdiget对象所用的内存,widget的operator new会返回一个指针,指向分配所得.widget析构函数会管理global new_handler,它会自动将widget’s operator new 被调用前的那个global new-handler恢复回来


class NewHandlerHolder {
public:
	explicit NewHandlerHolder(std::new_handler nh)://取得目前new-handler
		handler(nh){}
	NewHandlerHolder() {      //释放它
		std::set_new_handler(handler);
	}
private:
	std::new_handler handler;//记录下来
	NewHandlerHolder(const NewHandlerHolder&);//阻止copying
	NewHandlerHolder& operator=(const NewHandlerHolder&);
};
 
//对类Widget内的new操作符进行定义
void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {
	NewHandlerHolder h(std::set_new_handler(currenthandler));//安装Widget的new-handler.
	return ::operator new(size);                             //分配内存或抛出异常。恢复global new-handler
}

于是Wiget的客户可以如下使用其new-handling:


void outOfMem();//函数声明。此函数在Widget对象分配失败时被调用
 
Widget::set_new_handler(outOfMem);//设定outOfMem为Widget的new-handling函数
 
Widget* pw1 = new Widget;//如果内存分配失败,调用outOfMem
 
std::string* ps = new std::string;//如果内存分配失败,调用global new-handling函数
 
Widget::set_new_handler(0);//设定Widget专属的new-handling函数为null  0表明关闭outOfMem函数的调用
 
Widget* pw2 = new Widget;//如果内存分配失败,立刻抛出异常。

总结:

set_new_handler允许客户指定一个函数,在内存分配无法获得满足时调用.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值