Effective C++ 7

7.预先准备足够的内存情况。

new当内存分配请求无法完成,它会抛出一个异常,怎么办异常,这是一个非常现实的,绝对必要的所遇到的问题后。

于c一般使用宏来分配内存和测试分发成功。c++中产阶级似下面的函数:

#define NEW(PTR,TYPE)    
try { (PTR) = new TYPE;}  
	catch (std::bad_alloc& ){assert(0);}
catch 的std::bad_alloc为new 操作符中 不能满足内存分配请求时抛出的异常类型。

assert是在<assert.h>中宏,或者带命名空间的<cassert> 。宏检測传给它的表达式的值是否为0,假设是0,就会发出一条出错信息,并调用abort。assert在未定义标准宏NDEBUG时,即仅仅在调试状态中这么做。当产品公布后,即定义了NDEBUG后,assert什么也不做。

但使用宏是不够的,由于其仅仅能进行简单的一个基本数据类型的内存分配,而对于数组以及有构造函数的数据类型无法使用。

能够考虑重载operator new 。

而经常使用的简单的出错处理方法是,通过设置一个出错处理函数,使内存分配请求不能满足时,调用这个处理函数。

由于operator new 操作符在不能满足请求时。会在抛出异常前调用客户指定的一个出错处理函数。这个函数称为new-handler函数。

指定出错处理函数要用到set_new_handler 函数,该函数位于头文件<new>中,其定义例如以下:

new_handler __cdecl set_new_handler(_In_opt_ new_handler)
	_THROW0();

而new_handler的定义例如以下:

typedef void (__cdecl * new_handler) ();
new_handler为指向一个没有參数没有返回值的函数。而set_new_handler函数是一个输入參数为 operator new 分配内存失败时调用的出错处理函数的指针。返回值为set_new_handler函数没调用之前的已经在起作用的旧的函数处理函数的指针。

用法例如以下:

void noMoreMemory(){
	cerr<<"123"; 
	abort();
}
int main(){
	set_new_handler(noMoreMemory);
	int *p = new int [ 0x1fffffff ];
真正在程序中,new_handler函数不是简单的检測出错然后停止程序。而是要去处理出错,即通过一些措施,使下次内存分配能够成功。一个好的new_handler函数从下面几个方向入手:

1.产生很多其它的可用内存。若在程序启动时预留一大块内存。

然后失败时释放出这些内存供使用。

2.安装还有一个不同版本号的new_handler函数。通过一个新的能够获得资源的函数来获得很多其它资源,或者使用一些全局变量来改变自身的行为。

3.卸载new_handler。

分配无法成功,直接返回抛出标准的std::bad_alloc异常。
4.抛出bad_alloc异常或bad_alloc的派生异常。

5.没有返回,即如上所看到的,调用abort或exit。

类中的内存分配出错能够有自己重载的类的new操作符和 set_new_handler来实现。而这些函数与重载都是类的静态成员。

首先,类中要有一个静态成员 currentHandler来保存当前使用的new_handler函数。

对于set_new_handler。它仅仅是将类内的指针进行更换,以及返回旧的指针。而标准版本号也是如此做的。

对于operator new 。类中的重载new操作符,仅仅是简单的调用原有的new操作符操作,仅仅是错误处理用上类中设置的新的出错处理函数,所以其做法仅仅是用全局的set_new_handler()设置当前类中的currentHandler为处理函数,分配内存后或者异常报错前,恢复就可以。

代码例如以下:

class A{
public:
	static void* operator new (size_t size);
	static new_handler set_new_handler(new_handler p);
private:
	static new_handler currentHandler;
};
new_handler A::currentHandler;
new_handler A::set_new_handler(new_handler p){
	new_handler t = currentHandler;
	currentHandler = p;
	return t;
}
void* A::operator new(size_t size){
	new_handler globalHandler = std::set_new_handler(currentHandler);
	void* memory;
	try{
		memory = ::operator new(size);//::operator new 表示为全局的new操作符。

} catch(std::bad_alloc&){ std::set_new_handler(globalHandler); throw; } std::set_new_handler(globalHandler); return memory; }

而要做到非常好的代码重用,即对不论什么一个类都能轻松的实现以上代码实现的内容,能够创建一个混合风格的基类,这样的基类同意子类继承它的某一特定功能,如这里的new操作符的出错处理。

混合风格?43.





版权声明:本文博主原创文章,博客,未经同意不得转载。

原文地址:https://www.cnblogs.com/mengfanrong/p/4887405.html