原则49:了解new-handler的行为

本原则是针对在多线程环境下内存中动态存储区也就是堆中空间资源的访问而产生的,因为堆属于全局性资源,每个线程都试图去使用它,又因为每个线程是互斥地使用资源,那自然就会存在一个先到先得的问题,这就是所谓的竞速。你要知道堆空间也是有限的,于是就可能出现当某个线程是要使用堆空间时,堆却没有足够的空间提供给这个线程使用的时候。这个时候你再使用new来分配空间就会失败。虽然C++中提供了默认的处理过程,但是有的时候你就是希望自定义整个new的过程,那该如何是好?本原则就是来帮你解决这个问题的。
在这里你要知道C++是如何处理动态内存分配不足的问题的。以前如果遇到这种情况new会直接返回一个null,现在一般是返回一个bad_alloc异常。C++处理new异常通常有一个指向错误处理函数的函数指针new-handler,它负责对new分配不成功的处理。还有一个使用这个函数指针进行异常逻辑处理的函数叫set_new_handler,它们都在new头文件里面。
有趣的是这个set_new_handler是以new-handler为参数并以new-handler为返回值的,那又是怎么回事呢?作为参数的这个new-handler是指new分配错误时被调用的错误处理函数,注意!这个处理函数不一定非要是系统的库函数,它也可以是用户自定义的,不过因为new-handler是一个无参数无返回值的函数的指针,所以这个错误处理函数也必须是这样的一个函数。而那个返回的new-handler指向的是set_new_handler被调用前正在被执行的new-handler类型函数。在这里我对我自己的理解表示不确定。
这样只要new分配不成功它就不断地接受新的new-handler返回旧的new-handler知道new能分配成功。这样,设计一个良好的new-handler必须做到以下几点:
1、让可用内存更多。这一点首先要做到有足够的可供分配的内存空间,其次就是每次调用new-handler的时候就要及时释放掉那些没有分配成功的内存空间;
2、安装另一个new-handler。用更强大的new-handler替换当前的new-handler;
3、卸载new-handler。如果没有可用的new-handler,就将参数new-handler置为null使异常抛出;
4、抛出bad_alloc异常;
5、直接abort或者exit结束,啥也不做。
对于实现自定义new-handler和set_new_handler,作者的思想是在自定义接口中去调用这些系统函数来完成自定义功能,具体来说你就是在类内实现就好了。在此作者给了个例子:



从上图可见,主要就是在类中自定义两个公有的static接口,这样每个类的实例都可以使用这俩接口。其中一个是new的重载函数,另一个是set-new-handler。它还有一个私有的static的new-handler类型的指针,用来set-new-handler被调用前正在被使用的new-handler函数。这个set-new-handler所做的事情就是先把当前正在运行的new-handler函数保存起来,然后更改currentHandler的指向为新的new-handler,最后返回那个保存起来的new-handler。
这个被重载的new主要完成以下工作:
Step 1、在发生错误的时候调用标准的set-new-handler,这会将set-new-handler的参数置为新的global-new-handler,我想这个global-new-handler是系统提供的new-handler吧;
Step 2、global new会被调用,我想它也就是系统提供的那个new吧。如果new失败了,那么这个new会去调用类中的new-handler,因为由Step 1可知此时的new-handler实际上是系统的new-handler。如果这个系统的new-handler还是无法解决问题,它只能抛出bad-alloc异常。不过在这之前,类中的new必须把原来的系统的new-handler作为类中的set-new-handler的返回值来恢复系统的new-handler。为了先前的new-handler能得到恢复,类必须把先前的new-handler作为资源来管理;
Step 3、如果系统的new能分配成功,那么类中的new就应该返回该内存的指针,析构函数必须把先前的new-handler恢复回去。
因为这个方案并不因类的不同而不同,所以可以考虑把它做成父类的模版,让各个子类去继承这个特性,于是在这里作者提到了奇异递归模版模式,简称CRTP(Curiously Recurring Template Pattern)。它的样子大致如下。



可以看出一个父类是以子类类型来进行特化的。
文中还提到为了支持以前在旧规范时候写出来的代码,C++标准委员会提供了另一种new它在失败时直接返回null,它被称为nothrow形式的new。其使用形式如下:

这种new不好,因为它具有局限性,它只能管住当前代码后续代码它就管不了了,所以相比之下还是抛出异常的new比较好。
总结:
1、作为set-new-handler函数中的参数的new-handler允许用户自定义,它在内存分配不足时被调用。
2、Nothrow new太局限,它只适合于一段代码,对于后续的构造函数什么的抛出的异常却束手无策。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,834评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,599评论 18 399
  • 阅读目录前言new与malloc的10点区别1. 申请的内存所在位置2.返回类型安全性3.内存分配失败时的返回值4...
    yangqi916阅读 1,978评论 0 4
  • 朦胧尘世朦胧中,一场烟雨一梦休。 原想世外花田下,朝闻鸟鸣暮水流。 奈何生身不独有,牵挂牵绊扰梦幽。 若一世长久纷...
    草木萦心阅读 105评论 0 1
  • Hi,大家好!这是一个有关唐僧师徒四人取经之后回家乡创业的故事,每篇故事都是我们团队成员结合当下互联网热点词汇编写...
    硅谷堂阅读 526评论 0 2