多线程下的内存管理与单线程下是完全不同的,因为heap是一个可以被全局改动的资源,所以所有的线程都有可能去访问这一资源,这回导致很多的race_conditions。

 
当operator new未取得想要的内存的时候,会调用一个用户指定的处理函数,new_handler。 这个函数可以使用set_new_handler来进行指定。

 namespace std{
typedef void(*new_handler)();//没有参数以及返回值
new_handler set_new_handler(new_handler p) throw();
}
当operator new无法满足内存申请条件的时候,其就会不停的调用new-handler函数,所以说一个设计良好的new-handler应该需要满足下面的要求:
    让更多的内存被使用
    当当前的handler无法满足条件的时候,安装另一个new-handler.
    卸除new_handler,将null指针传给set_new_handler,,此时operator new 在无法分配内存的时候就会抛出异常
    抛出bad_alloc异常:这样的异常会被传播到内存的索求处
    不返回:调用abort或者exit
 
 
当需要以不同的方式去处理不同的class内存分配失败的情况的时候,应该为相应的特殊的class提供自己的set_new_handler以及operator_new。这样operator new会在分配内存的时候确保使用class专属的new_handler替代global的new handler.
 
一个Widget分配资源的简单例子:

 class NewHandlerHolder{
public:
explicit NewHandlerHolder(std::new_handler nh)
:handler(nh){}
~NewHandlerHolder()
std::set_new_handler(handler); //将状态恢复到之前的状态
private:
new_handler handler;
NewHandlerHolder(const NewHandlerHolder &); //禁止这两种操作
NewHandlerHolder & operator(const NewHandlerHolder &);
};

上面这个就可以被自定义的一个类所使用了:

 void * Widget::operator new(std::size_t size) throw (std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));//使用上面的RAII将handler资源正确的管理。
return ::operator new(size);//使用自定义的new
}

实际上,可以将上面的NewHandlerHolder设计成为一个基类模板,这样derived_class科技继承他们需要的set_new_handler以及operator_new,template用于保证每一个derived_class获得一个实体互异的currentHandler成员变量。下为这个模板:

 template<typename T>   //这里的typename T 并未被使用,作用下面会说
class NewHandlerSupport{
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void * operator new(std::size_t size) throw(std::bad_alloc);
...
private:
static std::new_handler currentHandler;
};
template<typename T>
static std::new_handler
NewHandlerSupport<T> set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
template<typename T>
static void *
NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator(size);//调用全局的operatornew,防止递归的调用自己。
}

有了这个模板,那么为Widget提供专属的set_new_handler以及operator都是很容易的了。继承上面的模板并特例化就可以了:

 class Widget : public NewHandlerSupport<Widget>{
...
};
这样就有了专属的set_new_handler以及operator new。
上买了的typename T 没有被使用,实际上也不需要, 这个T的目的只是为了使得不同的继承自NewHandlerSupport的子类有着其不同的实例函数。(主要是为了static变量,currentHandler)。T只是用来区分不同的derived_class. (因为上面T实例化成了Widget)
 
还有就是关于nothrow的问题,使用new (std::nothrow) Widget不会在new上产生异常,只会返回一个null指针,但是如果new正常还有可能在构造过程中产生异常,因此依然没有异常保证。没事不要用new (std::nothrow) sth;
 
小结:
    set_new_handler允许用户指定一个函数在内存无法分配时调用
    Nothrow new只能保证new不抛异常,构造仍然得不到保证。
 

条款49:了解new-handle行为的更多相关文章

  1. STL笔记(5)条款49:学习破解有关STL的编译器诊断信息

    STL笔记(5)条款49:学习破解有关STL的编译器诊断信息 条款49:学习破解有关STL的编译器诊断信息 用一个特定的大小定义一个vector是完全合法的, vector<int> v( ...

  2. EC读书笔记系列之19:条款49、50、51、52

    条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...

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

    set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用. Nothorw new 是一个颇为局限的工具,因为它只适用于内存分配:后继的构造函数调用还是可能抛出异常.

  4. Effective C++阅读笔记 较详细 复杂条款带样例

    一.让自己习惯C++ 条款01:视C++为一个语言联邦 C++可视为: C:以C为基础. 面向对象的C++:添加面向对象特性. 模板C++:泛型编程概念,使用模板. STL:使用STL的容器.迭代器. ...

  5. 《More Effective C++》 条款5 谨慎定义类型转换函数

    ---恢复内容开始--- C++编译器能够在两种数据类型之间进行隐式转换(implicit conversions),它继承了C语言的转换方法,例如允许把char隐式转换为int和从short隐式转换 ...

  6. 《Effective C++》定制new和delete:条款49-条款52

    条款49:了解new-handler的行为 当operator new无法分配出内存会抛出异常std::bad_alloc 抛出异常前会反复调用用户自定义的new-handler函数直至成功分配内存 ...

  7. Effective C++ 50条款

    条款1:尽量用const和inline而不用#define 以const 行使常量折叠,用inline 代替常用操作的宏定义,而且库里面有很多常用函数可用.当然不能抛弃宏,宏还是很有用滴.偶最近才发现 ...

  8. MoreEffectiveC++Item35 条款27: 要求或禁止对象产生于heap中

    一 要求对象产生在heap中 阻止对象产生产生在non-heap中最简单的方法是将其构造或析构函数声明在private下,用一个public的函数去调用起构造和析构函数 class UPNumber ...

  9. C++异常处理:try,catch,throw,finally的用法

    写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使 ...

随机推荐

  1. 隐马尔可夫模型(hidden Markov model,HMM)

    定义: 隐马尔科夫模型是关于时序的概率模型,描述由一个隐藏的马尔可夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测而产生观测随机序列的过程. 隐马尔科夫模型由初始概率分布.状态转移概率分布 ...

  2. 20170523 BSEG替代付款条件-ZTERM 天数-ZBD1T

    增强方式:替代,[替代基本用在FICO模块]BTE增强方式应用更广,需要学习总结. 程序:ZRGGBS* 步骤 1,SE16N:GB01 将 ZBD1T排除标记置为空,[注意,此更改跨client,d ...

  3. ABAP权限检查,TCode与权限对象进行关联

    一.确认权限对象,和关联字段: Tcode:SU21 维护权限对象例如"M_MSEG_WMB",它关联字段为'WERKS'M_MSEG_WMB 物料凭证:工厂 二.在ABAP代码中 ...

  4. 升级到tomcat8遇到The method getDispatcherType() is undefined for the type HttpServletRequest

    今天升级到tomcat8,发现原来的项目不能运行了,遇到下面的错误:The method getDispatcherType() is undefined for the type HttpServl ...

  5. re模块(Python中的正则表达式)

    re模块 正则表达式本身是一种小型的.高度专业化的编程语言,而在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配.正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎 ...

  6. 自定义Cell需要注意的问题

    使用xib创建cell时需要在设置单元格样式时使用[[NSBundel mainBundel] loadNibName:@“xib的文件名”owner:self option:nil][0]来初始化单 ...

  7. JPEGView——专业、免费、开源的图像浏览器

    虽叫JPEGView,它不仅支持jpeg图像格式,主流的图像格式它都支持. 试一试你就知道它有多强大了.

  8. jQuery UI入门

    jQuery UI是jQuery的一个插件集,为jQuery的核心库添加了新的功能. jQUery UI库可以从http://jquery.com下载. 下载一个ZIP文件jquery-ui-1.9. ...

  9. $用python实现快速排序算法

    本文主要介绍用python实现基本的快速排序算法,体会一下python的快排代码可以写得多么简洁. 1. 三言两语概括算法核心思想 先从待排序的数组中找出一个数作为基准数(取第一个数即可),然后将原来 ...

  10. LVS/DR 配置

    LVS/DR 配置 实验环境 三台主机:Linux Centos 6.4 32位 调度器Director:192.168.1.160(公网IP).192.168.1.100(VIP) HTTP真实服务 ...