C++,也省点心,从此不再关心 new 内存分配失败
开了个虚拟机,开了5个VS2015,把内存占得只剩不到64M,但发现程序还是跑得蛮正常的,居然没有程序崩(没有看到)。
看几张内存使用过载截图:
4G的内存已经飙到了极限,但是程序没崩。。。
不管他们作了什么手段,脚本语言写得多了,现在我也不想管那么多了。如果 new 失败了,要么就让它抛异常,不处理,直接让程序崩,要么不让 new 抛异常,永远(?)不抛。 不过我还是觉得后者要妥当些。于是就决定这样干下去。脚本语言等那么耗内存都不曾管,我大C++管它干嘛。
要让 new 不抛异常,蛮简单,可以先看看 new 的实现(VS2013,/vc/crt/src/new.cpp):
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{ // report no memory
_THROW_NCEE(_XSTD bad_alloc, );
}
return (p);
}
,可以看到,new 调用C语言标准库的 malloc 进行内存分配,并且在内存分配失败的时候会调用 _callnewh 来调用我们自定义的 new-handler,如果 new-handler 返回非零,new 运算符就会再次尝试内存分配,直到分配内存或 new-handler 返回了零,那么 new 此时将会以抛异常的形式来表示内存分配失败。
所以如果我们设置了一个自定义的 new-handler(默认为空)回调函数,那么每次 new 分配失败的时候,该回调函数会被调用,一次或多次。而如果我们的 new-hander 总是返回非零的话,new 也就不会再抛异常了。放心码代码了!
而 new-handler 的原型、设置、获取也很简单:
typedef int (__cdecl * new_handler) (size_t);
new_handler __cdecl set_new_handler(new_handler pnh);
new_handler __cdecl get_new_handler();
。那么,简单地像下面这样做就可以了(我一般在进入main的函数就这样干):
// C++11 之前
int my_new_handler(size_t) {
return 1;
}
set_new_handler(my_new_handler);
// C++11及以后可以用lambda了
set_new_handler([](size_t){return 1;});
,new-handler 全局只有一个,也就是说,如果有其它地方调用了设置的话,会被覆盖掉的。除非再设置回来。